//	Project: Handle Template Library
//	File:    CProc.h
//	Author:  Paul Bludov
//	Date:    2002-11-04
//
//	Description:
//		C++ wrapper for Win32 JobObject, process, thread, etc.
//
//	Update History:
//		NONE
//		
/////////////////////////////////////////////////////////////////////////////

#ifndef __HTLPROC_H__
#define __HTLPROC_H__

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include "htlhandle.h"

/////////////////////////////////////////////////////////////////////////////
// Classes in this file
//
// CProcessT<t_bManaged>
// CThreadT<t_bManaged>
// CJobObjectT<t_bManaged>
// CTokenT<t_bManaged>
// CToolhelpSnapshotT<t_bManaged>
//

namespace HTL
{

// Helpers

inline bool IsValidProcess
	( __in HANDLE hProcess
	)
{
#ifdef _DEBUG
	if (NULL != hProcess)
	{
		// The current process pseudohandle is INVALID_HANDLE_VALUE (-1)
		//
		if ((HANDLE)-1 == hProcess)
			return true;

		DWORD nError = ::GetLastError();
		_ASSERTE(0 != ::GetPriorityClass(hProcess)
			|| ::GetLastError() != ERROR_INVALID_HANDLE);
		::SetLastError(nError);
	}
#endif
	return NULL != hProcess;
}

inline bool IsValidThread
	( __in HANDLE hThread
	)
{
#ifdef _DEBUG
	if (NULL != hThread)
	{
		// The current thread pseudohandle is -2
		//
		if ((HANDLE)-2 == hThread)
			return true;

		DWORD nError = ::GetLastError();
		_ASSERTE(THREAD_PRIORITY_ERROR_RETURN != ::GetThreadPriority(hThread)
			|| ::GetLastError() != ERROR_INVALID_HANDLE);
		::SetLastError(nError);
	}
#endif
	return NULL != hThread;
}

inline BOOL CreateProcess
	( __in_opt    LPCSTR                lpApplicationName
	, __inout_opt LPSTR                 lpCommandLine
	, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
	, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
	, __in        BOOL                  bInheritHandles
	, __in        DWORD                 dwCreationFlags
	, __in_opt    LPVOID                lpEnvironment
	, __in_opt    LPCSTR                lpCurrentDirectory
	, __in        LPSTARTUPINFOA        lpStartupInfo
	, __out_opt   LPHANDLE              lphProcess   = NULL
	, __out_opt   LPHANDLE              lphThread    = NULL
	, __out_opt   LPDWORD               lpnProcessId = NULL
	, __out_opt   LPDWORD               lpnThreadId  = NULL
	)
{
	_ASSERTE(lpStartupInfo);
	_ASSERTE(lpApplicationName || lpCommandLine);
	PROCESS_INFORMATION pi = {0};
	BOOL b;

	b = ::CreateProcessA(lpApplicationName, lpCommandLine
		, lpProcessAttributes, lpThreadAttributes, bInheritHandles
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, &pi);
	if (b)
	{
		if (lphProcess)
			*lphProcess = pi.hProcess;
		else
			::CloseHandle(pi.hProcess);
		if (lphThread)
			*lphThread = pi.hThread;
		else
			::CloseHandle(pi.hThread);

		if (lpnProcessId)
			*lpnProcessId = pi.dwProcessId;
		if (lpnThreadId)
			*lpnThreadId = pi.dwThreadId;
	}
	return b;
}

inline BOOL CreateProcess
	( __in_opt    LPCWSTR               lpApplicationName
	, __inout_opt LPWSTR                lpCommandLine
	, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
	, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
	, __in        BOOL                  bInheritHandles
	, __in        DWORD                 dwCreationFlags
	, __in_opt    LPVOID                lpEnvironment
	, __in_opt    LPCWSTR               lpCurrentDirectory
	, __in        LPSTARTUPINFOW        lpStartupInfo
	, __out_opt   LPHANDLE              lphProcess   = NULL
	, __out_opt   LPHANDLE              lphThread    = NULL
	, __out_opt   LPDWORD               lpnProcessId = NULL
	, __out_opt   LPDWORD               lpnThreadId  = NULL
	)
{
	_ASSERTE(lpStartupInfo);
	_ASSERTE(lpApplicationName || lpCommandLine);
	PROCESS_INFORMATION pi = {0};
	BOOL b;

	b = ::CreateProcessW(lpApplicationName, lpCommandLine
		, lpProcessAttributes, lpThreadAttributes, bInheritHandles
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, &pi);
	if (b)
	{
		if (lphProcess)
			*lphProcess = pi.hProcess;
		else
			::CloseHandle(pi.hProcess);
		if (lphThread)
			*lphThread = pi.hThread;
		else
			::CloseHandle(pi.hThread);

		if (lpnProcessId)
			*lpnProcessId = pi.dwProcessId;
		if (lpnThreadId)
			*lpnThreadId = pi.dwThreadId;
	}
	return b;
}

inline BOOL CreateProcess
	( __in_opt    LPCSTR         lpApplicationName
	, __inout_opt LPSTR          lpCommandLine      = NULL
	, __in        DWORD          dwCreationFlags    = 0
	, __in_opt    LPSTARTUPINFOA lpStartupInfo      = NULL
	, __in_opt    LPVOID         lpEnvironment      = NULL
	, __in_opt    LPCSTR         lpCurrentDirectory = NULL
	, __out_opt   LPHANDLE       lphProcess         = NULL
	, __out_opt   LPHANDLE       lphThread          = NULL
	, __out_opt   LPDWORD        lpnProcessId       = NULL
	, __out_opt   LPDWORD        lpnThreadId        = NULL
	)
{
	_ASSERTE(lpApplicationName || lpCommandLine);
	STARTUPINFOA si = {0};

	if (!lpStartupInfo)
	{
		si.cb = sizeof(STARTUPINFOA);
		lpStartupInfo = &si;
	}
	return CreateProcess(lpApplicationName, lpCommandLine, NULL, NULL, FALSE
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, lphProcess, lphThread, lpnProcessId, lpnThreadId);
}

inline BOOL CreateProcess
	( __in_opt    LPCWSTR        lpApplicationName
	, __inout_opt LPWSTR         lpCommandLine      = NULL
	, __in        DWORD          dwCreationFlags    = 0
	, __in_opt    LPSTARTUPINFOW lpStartupInfo      = NULL
	, __in_opt    LPVOID         lpEnvironment      = NULL
	, __in_opt    LPCWSTR        lpCurrentDirectory = NULL
	, __out_opt   LPHANDLE       lphProcess         = NULL
	, __out_opt   LPHANDLE       lphThread          = NULL
	, __out_opt   LPDWORD        lpnProcessId       = NULL
	, __out_opt   LPDWORD        lpnThreadId        = NULL
	)
{
	_ASSERTE(lpApplicationName || lpCommandLine);
	STARTUPINFOW si = {0};

	if (!lpStartupInfo)
	{
		si.cb = sizeof(STARTUPINFOW);
		lpStartupInfo = &si;
	}
	return CreateProcess(lpApplicationName, lpCommandLine, NULL, NULL, FALSE
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, lphProcess, lphThread, lpnProcessId, lpnThreadId);
}

inline BOOL CreateProcessAsUser
	( __in_opt    HANDLE                hToken
	, __in_opt    LPCSTR                lpApplicationName
	, __inout_opt LPSTR                 lpCommandLine
	, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
	, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
	, __in        BOOL                  bInheritHandles
	, __in        DWORD                 dwCreationFlags
	, __in_opt    LPVOID                lpEnvironment
	, __in_opt    LPCSTR                lpCurrentDirectory
	, __in        LPSTARTUPINFOA        lpStartupInfo
	, __out_opt   LPHANDLE              lphProcess   = NULL
	, __out_opt   LPHANDLE              lphThread    = NULL
	, __out_opt   LPDWORD               lpnProcessId = NULL
	, __out_opt   LPDWORD               lpnThreadId  = NULL
	)
{
	_ASSERTE(lpStartupInfo);
	_ASSERTE(lpApplicationName || lpCommandLine);
	PROCESS_INFORMATION pi = {0};
	BOOL b;

	b = ::CreateProcessAsUserA(hToken, lpApplicationName, lpCommandLine
		, lpProcessAttributes, lpThreadAttributes, bInheritHandles
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, &pi);
	if (b)
	{
		if (lphProcess)
			*lphProcess = pi.hProcess;
		else
			::CloseHandle(pi.hProcess);
		if (lphThread)
			*lphThread = pi.hThread;
		else
			::CloseHandle(pi.hThread);

		if (lpnProcessId)
			*lpnProcessId = pi.dwProcessId;
		if (lpnThreadId)
			*lpnThreadId = pi.dwThreadId;
	}
	return b;
}

inline BOOL CreateProcessAsUser
	( __in_opt    HANDLE                hToken
	, __in_opt    LPCWSTR               lpApplicationName
	, __inout_opt LPWSTR                lpCommandLine
	, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
	, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
	, __in        BOOL                  bInheritHandles
	, __in        DWORD                 dwCreationFlags
	, __in_opt    LPVOID                lpEnvironment
	, __in_opt    LPCWSTR               lpCurrentDirectory
	, __in        LPSTARTUPINFOW        lpStartupInfo
	, __out_opt   LPHANDLE              lphProcess   = NULL
	, __out_opt   LPHANDLE              lphThread    = NULL
	, __out_opt   LPDWORD               lpnProcessId = NULL
	, __out_opt   LPDWORD               lpnThreadId  = NULL
	)
{
	_ASSERTE(lpStartupInfo);
	_ASSERTE(lpApplicationName || lpCommandLine);
	PROCESS_INFORMATION pi = {0};
	BOOL b;

	b = ::CreateProcessAsUserW(hToken, lpApplicationName, lpCommandLine
		, lpProcessAttributes, lpThreadAttributes, bInheritHandles
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, &pi);
	if (b)
	{
		if (lphProcess)
			*lphProcess = pi.hProcess;
		else
			::CloseHandle(pi.hProcess);
		if (lphThread)
			*lphThread = pi.hThread;
		else
			::CloseHandle(pi.hThread);

		if (lpnProcessId)
			*lpnProcessId = pi.dwProcessId;
		if (lpnThreadId)
			*lpnThreadId = pi.dwThreadId;
	}
	return b;
}

inline BOOL CreateProcessAsUser
	( __in_opt    HANDLE                hToken
	, __in_opt    LPCSTR                lpApplicationName
	, __inout_opt LPSTR                 lpCommandLine
	, __in        DWORD                 dwCreationFlags
	, __in        LPSTARTUPINFOA        lpStartupInfo
	, __in_opt    LPVOID                lpEnvironment
	, __in_opt    LPCSTR                lpCurrentDirectory
	, __out_opt   LPHANDLE              lphProcess   = NULL
	, __out_opt   LPHANDLE              lphThread    = NULL
	, __out_opt   LPDWORD               lpnProcessId = NULL
	, __out_opt   LPDWORD               lpnThreadId  = NULL
	)
{
	_ASSERTE(lpApplicationName || lpCommandLine);
	STARTUPINFOA si = {0};

	if (!lpStartupInfo)
	{
		si.cb = sizeof(STARTUPINFOA);
		lpStartupInfo = &si;
	}
	return CreateProcessAsUser(hToken, lpApplicationName, lpCommandLine, NULL, NULL, FALSE
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, lphProcess, lphThread, lpnProcessId, lpnThreadId);
}

inline BOOL CreateProcessAsUser
	( __in_opt    HANDLE                hToken
	, __in_opt    LPCWSTR               lpApplicationName
	, __inout_opt LPWSTR                lpCommandLine
	, __in        DWORD                 dwCreationFlags
	, __in        LPSTARTUPINFOW        lpStartupInfo
	, __in_opt    LPVOID                lpEnvironment
	, __in_opt    LPCWSTR               lpCurrentDirectory
	, __out_opt   LPHANDLE              lphProcess   = NULL
	, __out_opt   LPHANDLE              lphThread    = NULL
	, __out_opt   LPDWORD               lpnProcessId = NULL
	, __out_opt   LPDWORD               lpnThreadId  = NULL
	)
{
	_ASSERTE(lpApplicationName || lpCommandLine);
	STARTUPINFOW si = {0};

	if (!lpStartupInfo)
	{
		si.cb = sizeof(STARTUPINFOW);
		lpStartupInfo = &si;
	}
	return CreateProcessAsUser(hToken, lpApplicationName, lpCommandLine, NULL, NULL, FALSE
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, lphProcess, lphThread, lpnProcessId, lpnThreadId);
}

#if (_WIN32_WINNT >= 0x0500)

inline BOOL CreateProcessWithLogon
	( __in        LPCWSTR        lpUsername
	, __in_opt    LPCWSTR        lpDomain
	, __in        LPCWSTR        lpPassword
	, __in        DWORD          dwLogonFlags
	, __in_opt    LPCWSTR        lpApplicationName
	, __inout_opt LPWSTR         lpCommandLine
	, __in        DWORD          dwCreationFlags
	, __in        LPSTARTUPINFOW lpStartupInfo
	, __in_opt    LPVOID         lpEnvironment
	, __in_opt    LPCWSTR        lpCurrentDirectory
	, __out_opt   LPHANDLE       lphProcess   = NULL
	, __out_opt   LPHANDLE       lphThread    = NULL
	, __out_opt   LPDWORD        lpnProcessId = NULL
	, __out_opt   LPDWORD        lpnThreadId  = NULL
	)
{
	_ASSERTE(lpApplicationName || lpCommandLine);
	STARTUPINFOW si = {0};
	PROCESS_INFORMATION pi = {0};
	BOOL b;

	if (!lpStartupInfo)
	{
		si.cb = sizeof(STARTUPINFOW);
		lpStartupInfo = &si;
	}
	b = ::CreateProcessWithLogonW(lpUsername, lpDomain, lpPassword
		, dwLogonFlags, lpApplicationName, lpCommandLine
		, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo
		, &pi);
	if (b)
	{
		if (lphProcess)
			*lphProcess = pi.hProcess;
		else
			::CloseHandle(pi.hProcess);
		if (lphThread)
			*lphThread = pi.hThread;
		else
			::CloseHandle(pi.hThread);

		if (lpnProcessId)
			*lpnProcessId = pi.dwProcessId;
		if (lpnThreadId)
			*lpnThreadId = pi.dwThreadId;
	}
	return b;
}

inline BOOL CreateProcessWithToken
	( __in        HANDLE         hToken
	, __in        DWORD          dwLogonFlags
	, __in_opt    LPCWSTR        lpApplicationName
	, __inout_opt LPWSTR         lpCommandLine
	, __in        DWORD          dwCreationFlags
	, __in        LPSTARTUPINFOW lpStartupInfo
	, __in_opt    LPVOID         lpEnvironment
	, __in_opt    LPCWSTR        lpCurrentDirectory
	, __out_opt   LPHANDLE       lphProcess   = NULL
	, __out_opt   LPHANDLE       lphThread    = NULL
	, __out_opt   LPDWORD        lpnProcessId = NULL
	, __out_opt   LPDWORD        lpnThreadId  = NULL
	)
{
	_ASSERTE(lpApplicationName || lpCommandLine);
	STARTUPINFOW si = {0};
	PROCESS_INFORMATION pi = {0};
	BOOL b;

	if (!lpStartupInfo)
	{
		si.cb = sizeof(STARTUPINFOW);
		lpStartupInfo = &si;
	}
	b = CreateProcessWithTokenW(hToken, dwLogonFlags, lpApplicationName
		, lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory
		, lpStartupInfo, &pi);
	if (b)
	{
		if (lphProcess)
			*lphProcess = pi.hProcess;
		else
			::CloseHandle(pi.hProcess);
		if (lphThread)
			*lphThread = pi.hThread;
		else
			::CloseHandle(pi.hThread);

		if (lpnProcessId)
			*lpnProcessId = pi.dwProcessId;
		if (lpnThreadId)
			*lpnThreadId = pi.dwThreadId;
	}
	return b;
}

#endif // _WIN32_WINNT >= 0x0500

// Copy the code bytes into the remote process and execute
static HANDLE CreateRemoteThreadEx
	( __in      HANDLE                 hProcess
	, __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
	, __in      SIZE_T                 nStackSize
	, __in      LPTHREAD_START_ROUTINE lpStartAddress
	, __in      SIZE_T                 nStartRoutineSize
	, __in_opt  LPVOID                 lpParameter     = NULL
	, __in      SIZE_T                 nParameterSize  = 0
	, __in      DWORD                  dwCreationFlags = 0
	, __out_opt LPDWORD                lpnThreadId     = NULL
	, __out_opt LPVOID                *lplpCodeRemote  = NULL
	)
{
	_ASSERTE(lpStartAddress);
	_ASSERTE(nStartRoutineSize > 0);
	_ASSERTE(IsValidProcess(hProcess));
	const int	nAlignBytes = sizeof(INT_PTR) - 1;
	SIZE_T		nTotalSize, nBytesWritten, nStartRoutineSizeAligned;
	BOOL		b, bSuccessAll = FALSE;
	LPBYTE		lpnCodeRemote;
	HANDLE		hThread = NULL;

	// Allocate memory in the remote process's address space large 
	// enough to hold both thread routine and its parameter
	nStartRoutineSizeAligned = (nStartRoutineSize + nAlignBytes) & ~nAlignBytes;
	nTotalSize = nStartRoutineSizeAligned + nParameterSize;
	lpnCodeRemote = (LPBYTE)::VirtualAllocEx(hProcess, NULL, nTotalSize
		, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);

	if (lpnCodeRemote)
	{
		// Write a copy of thread routine to the remote process
		b = ::WriteProcessMemory(hProcess, lpnCodeRemote, lpStartAddress
			, nStartRoutineSize, &nBytesWritten);
		if (b && nBytesWritten == nStartRoutineSize)
		{
			if (nParameterSize)
			{
				// Write an aligned copy of parameter to the remote process
				b = ::WriteProcessMemory(hProcess
					, lpnCodeRemote + nStartRoutineSizeAligned, lpParameter
					, nParameterSize, &nBytesWritten);
				if (b && nBytesWritten == nParameterSize)
					bSuccessAll = TRUE;
			}
			else
				bSuccessAll = TRUE;
		}

		if (bSuccessAll)
			hThread = ::CreateRemoteThread(hProcess, lpThreadAttributes
				, nStackSize, (LPTHREAD_START_ROUTINE)lpnCodeRemote
				, lpnCodeRemote + nStartRoutineSizeAligned, dwCreationFlags
				, lpnThreadId);

		if (!hThread)
		{
			// Succeeded to allocate but failed to write or execute
			DWORD dwError = ::GetLastError();
			::VirtualFreeEx(hProcess, lpnCodeRemote, nTotalSize, MEM_DECOMMIT);
			::SetLastError(dwError);
		}
	}

	if (hThread && lplpCodeRemote)
		*lplpCodeRemote = lpnCodeRemote;

	return hThread;
}

inline HANDLE CreateRemoteThreadEx
	( __in      HANDLE                 hProcess
	, __in      LPTHREAD_START_ROUTINE lpStartAddress
	, __in      SIZE_T                 nStartRoutineSize
	, __in_opt  LPVOID                 lpParameter     = NULL
	, __in      SIZE_T                 nParameterSize  = 0
	, __in      DWORD                  dwCreationFlags = 0
	, __out_opt LPDWORD                lpnThreadId     = NULL
	, __out_opt LPVOID                *lplpCodeRemote  = NULL
	)
{
	return HTL::CreateRemoteThreadEx(hProcess, NULL, 0, lpStartAddress
		, nStartRoutineSize, lpParameter, nParameterSize, dwCreationFlags
		, lpnThreadId, lplpCodeRemote);
}

// CreateRemoteThreadEx causes a leak in the target process memory
// this routine should be called when remote thread finished
inline BOOL FreeRemoteThreadMemory
	( __in HANDLE hProcess
	, __in LPVOID lpCodeRemote
	, __in SIZE_T nStartRoutineSize
	, __in SIZE_T nParameterSize = 0
	)
{
	_ASSERTE(lpCodeRemote);
	_ASSERTE(nStartRoutineSize > 0);
	_ASSERTE(IsValidProcess(hProcess));
	const int	nAlignBytes = sizeof(INT_PTR) - 1;
	SIZE_T		nTotalSize, nStartRoutineSizeAligned;

	nStartRoutineSizeAligned = (nStartRoutineSize + nAlignBytes) & ~nAlignBytes;
	nTotalSize = nStartRoutineSizeAligned + nParameterSize;

	return ::VirtualFreeEx(hProcess, lpCodeRemote, nTotalSize, MEM_DECOMMIT);
}

/////////////////////////////////////////////////////////////////////////////
// Process

template<bool t_bManaged>
class CProcessT
	: public CHandleT<t_bManaged>
{
	typedef CHandleT<t_bManaged> Base;
public:
	CProcessT()
	{ }
	CProcessT
		( __in const CProcessT<true>& rProcess
		)
		: Base(rProcess)
	{ }
	CProcessT
		( __in const CProcessT<false>& rProcess
		)
		: Base(rProcess)
	{ }
	explicit CProcessT
		( __in HANDLE hProcess
		)
		: Base(hProcess)
	{ }

	CProcessT
		( __in_opt    LPCSTR                lpApplicationName
		, __inout_opt LPSTR                 lpCommandLine
		, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
		, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
		, __in        BOOL                  bInheritHandles
		, __in        DWORD                 dwCreationFlags
		, __in_opt    LPVOID                lpEnvironment
		, __in_opt    LPCSTR                lpCurrentDirectory
		, __in        LPSTARTUPINFOA        lpStartupInfo
		, __out_opt   LPHANDLE              lphThread    = NULL
		, __out_opt   LPDWORD               lpnProcessId = NULL
		, __out_opt   LPDWORD               lpnThreadId  = NULL
		)
	{
		Create(lpApplicationName, lpCommandLine, lpProcessAttributes
			, lpThreadAttributes, bInheritHandles, dwCreationFlags
			, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lphThread
			, lpnProcessId, lpnThreadId);
		_ASSERTE(IsValid());
	}

	CProcessT
		( __in_opt    LPCWSTR               lpApplicationName
		, __inout_opt LPWSTR                lpCommandLine
		, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
		, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
		, __in        BOOL                  bInheritHandles
		, __in        DWORD                 dwCreationFlags
		, __in_opt    LPVOID                lpEnvironment
		, __in_opt    LPCWSTR               lpCurrentDirectory
		, __in        LPSTARTUPINFOW        lpStartupInfo
		, __out_opt   LPHANDLE              lphThread    = NULL
		, __out_opt   LPDWORD               lpnProcessId = NULL
		, __out_opt   LPDWORD               lpnThreadId  = NULL
		)
	{
		Create(lpApplicationName, lpCommandLine, lpProcessAttributes
			, lpThreadAttributes, bInheritHandles, dwCreationFlags
			, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lphThread
			, lpnProcessId, lpnThreadId);
		_ASSERTE(IsValid());
	}

	CProcessT
		( __in_opt    LPCSTR         lpApplicationName
		, __inout_opt LPSTR          lpCommandLine      = NULL
		, __in        DWORD          dwCreationFlags    = 0
		, __in        LPSTARTUPINFOA lpStartupInfo      = NULL
		, __in_opt    LPVOID         lpEnvironment      = NULL
		, __in_opt    LPCSTR         lpCurrentDirectory = NULL
		, __out_opt   LPHANDLE       lphThread          = NULL
		, __out_opt   LPDWORD        lpnProcessId       = NULL
		, __out_opt   LPDWORD        lpnThreadId        = NULL
		)
	{
		Create(lpApplicationName, lpCommandLine, dwCreationFlags
			, lpStartupInfo, lpEnvironment, lpCurrentDirectory
			, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(IsValid());
	}

	CProcessT
		( __in_opt    LPCWSTR        lpApplicationName
		, __inout_opt LPWSTR         lpCommandLine      = NULL
		, __in        DWORD          dwCreationFlags    = 0
		, __in        LPSTARTUPINFOW lpStartupInfo      = NULL
		, __in_opt    LPVOID         lpEnvironment      = NULL
		, __in_opt    LPCWSTR        lpCurrentDirectory = NULL
		, __out_opt   LPHANDLE       lphThread          = NULL
		, __out_opt   LPDWORD        lpnProcessId       = NULL
		, __out_opt   LPDWORD        lpnThreadId        = NULL
		)
	{
		Create(lpApplicationName, lpCommandLine, dwCreationFlags
			, lpStartupInfo, lpEnvironment, lpCurrentDirectory
			, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(IsValid());
	}

	CProcessT
		( __in DWORD nProcessId
		, __in DWORD nDesiredAccess
		, __in BOOL  bInheritHandle = FALSE
		)
	{
		Open(nProcessId, nDesiredAccess, bInheritHandle);
		_ASSERTE(IsValid());
	}

	CProcessT<t_bManaged>& operator=
		( __in HANDLE h
		)
	{
		Base::operator=(h);
		return *this;
	}

	CProcessT<t_bManaged>& operator=
		( __in const CProcessT<true>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	CProcessT<t_bManaged>& operator=
		( __in const CProcessT<false>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	bool IsValid() const
	{
		return HTL::IsValidProcess(m_h);
	}

	HANDLE Create
		( __in_opt    LPCSTR                lpApplicationName
		, __inout_opt LPSTR                 lpCommandLine
		, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
		, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
		, __in        BOOL                  bInheritHandles
		, __in        DWORD                 dwCreationFlags
		, __in_opt    LPVOID                lpEnvironment
		, __in_opt    LPCSTR                lpCurrentDirectory
		, __in        LPSTARTUPINFOA        lpStartupInfo
		, __out_opt   LPHANDLE              lphThread    = NULL
		, __out_opt   LPDWORD               lpnProcessId = NULL
		, __out_opt   LPDWORD               lpnThreadId  = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(!IsValid());
		BOOL b;

		b = HTL::CreateProcess(lpApplicationName, lpCommandLine
			, lpProcessAttributes, lpThreadAttributes, bInheritHandles
			, dwCreationFlags, lpEnvironment, lpCurrentDirectory
			, lpStartupInfo, &m_h, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE Create
		( __in_opt    LPCWSTR               lpApplicationName
		, __inout_opt LPWSTR                lpCommandLine
		, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
		, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
		, __in        BOOL                  bInheritHandles
		, __in        DWORD                 dwCreationFlags
		, __in_opt    LPVOID                lpEnvironment
		, __in_opt    LPCWSTR               lpCurrentDirectory
		, __in        LPSTARTUPINFOW        lpStartupInfo
		, __out_opt   LPHANDLE              lphThread    = NULL
		, __out_opt   LPDWORD               lpnProcessId = NULL
		, __out_opt   LPDWORD               lpnThreadId  = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(!IsValid());
		BOOL b;

		b = HTL::CreateProcess(lpApplicationName, lpCommandLine
			, lpProcessAttributes, lpThreadAttributes, bInheritHandles
			, dwCreationFlags, lpEnvironment, lpCurrentDirectory
			, lpStartupInfo, &m_h, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE Create
		( __in      LPCSTR         lpApplicationName
		, __in_opt  LPSTR          lpCommandLine      = NULL
		, __in      DWORD          dwCreationFlags    = 0
		, __in_opt  LPSTARTUPINFOA lpStartupInfo      = NULL
		, __in_opt  LPVOID         lpEnvironment      = NULL
		, __in_opt  LPCSTR         lpCurrentDirectory = NULL
		, __out_opt LPHANDLE       lphThread          = NULL
		, __out_opt LPDWORD        lpnProcessId       = NULL
		, __out_opt LPDWORD        lpnThreadId        = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(!IsValid());
		BOOL b;

		b = HTL::CreateProcess(lpApplicationName, lpCommandLine
			, dwCreationFlags, lpStartupInfo, lpEnvironment, lpCurrentDirectory
			, &m_h, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE Create
		( __in      LPCWSTR        lpApplicationName
		, __in_opt  LPWSTR         lpCommandLine      = NULL
		, __in      DWORD          dwCreationFlags    = 0
		, __in_opt  LPSTARTUPINFOW lpStartupInfo      = NULL
		, __in_opt  LPVOID         lpEnvironment      = NULL
		, __in_opt  LPCWSTR        lpCurrentDirectory = NULL
		, __out_opt LPHANDLE       lphThread          = NULL
		, __out_opt LPDWORD        lpnProcessId       = NULL
		, __out_opt LPDWORD        lpnThreadId        = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(!IsValid());
		BOOL b;

		b = HTL::CreateProcess(lpApplicationName, lpCommandLine
			, dwCreationFlags, lpStartupInfo, lpEnvironment, lpCurrentDirectory
			, &m_h, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE CreateAsUser
		( __in_opt    HANDLE                hToken
		, __in_opt    LPCSTR                lpApplicationName
		, __inout_opt LPSTR                 lpCommandLine
		, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
		, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
		, __in        BOOL                  bInheritHandles
		, __in        DWORD                 dwCreationFlags
		, __in_opt    LPVOID                lpEnvironment
		, __in_opt    LPCSTR                lpCurrentDirectory
		, __in        LPSTARTUPINFOA        lpStartupInfo
		, __out_opt   LPHANDLE              lphThread    = NULL
		, __out_opt   LPDWORD               lpnProcessId = NULL
		, __out_opt   LPDWORD               lpnThreadId  = NULL
		)
	{
		_ASSERTE(lpStartupInfo);
		_ASSERTE(lpApplicationName || lpCommandLine);
		BOOL b;

		b = HTL::CreateProcessAsUser(hToken, lpApplicationName
			, lpCommandLine, lpProcessAttributes, lpThreadAttributes
			, bInheritHandles, dwCreationFlags, lpEnvironment
			, lpCurrentDirectory, lpStartupInfo, &m_h, lphThread
			, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE CreateAsUser
		( __in_opt    HANDLE                hToken
		, __in_opt    LPCWSTR               lpApplicationName
		, __inout_opt LPWSTR                lpCommandLine
		, __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes
		, __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes
		, __in        BOOL                  bInheritHandles
		, __in        DWORD                 dwCreationFlags
		, __in_opt    LPVOID                lpEnvironment
		, __in_opt    LPCWSTR               lpCurrentDirectory
		, __in        LPSTARTUPINFOW        lpStartupInfo
		, __out_opt   LPHANDLE              lphThread    = NULL
		, __out_opt   LPDWORD               lpnProcessId = NULL
		, __out_opt   LPDWORD               lpnThreadId  = NULL
		)
	{
		_ASSERTE(lpStartupInfo);
		_ASSERTE(lpApplicationName || lpCommandLine);
		BOOL b;

		b = HTL::CreateProcessAsUser(hToken, lpApplicationName
			, lpCommandLine, lpProcessAttributes, lpThreadAttributes
			, bInheritHandles, dwCreationFlags, lpEnvironment
			, lpCurrentDirectory, lpStartupInfo, &m_h, lphThread
			, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE CreateAsUser
		( __in      HANDLE         hToken
		, __in      LPCSTR         lpApplicationName
		, __in_opt  LPSTR          lpCommandLine      = NULL
		, __in      DWORD          dwCreationFlags    = 0
		, __in_opt  LPSTARTUPINFOA lpStartupInfo      = NULL
		, __in_opt  LPVOID         lpEnvironment      = NULL
		, __in_opt  LPCSTR         lpCurrentDirectory = NULL
		, __out_opt LPHANDLE       lphThread          = NULL
		, __out_opt LPDWORD        lpnProcessId       = NULL
		, __out_opt LPDWORD        lpnThreadId        = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		BOOL b;

		b = HTL::CreateProcessAsUser(hToken, lpApplicationName
			, lpCommandLine, dwCreationFlags, lpStartupInfo, lpEnvironment
			, lpCurrentDirectory, &m_h, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE CreateAsUser
		( __in      HANDLE         hToken
		, __in      LPCWSTR        lpApplicationName
		, __in_opt  LPWSTR         lpCommandLine      = NULL
		, __in      DWORD          dwCreationFlags    = 0
		, __in_opt  LPSTARTUPINFOW lpStartupInfo      = NULL
		, __in_opt  LPVOID         lpEnvironment      = NULL
		, __in_opt  LPCWSTR        lpCurrentDirectory = NULL
		, __out_opt LPHANDLE       lphThread          = NULL
		, __out_opt LPDWORD        lpnProcessId       = NULL
		, __out_opt LPDWORD        lpnThreadId        = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		BOOL b;

		b = HTL::CreateProcessAsUser(hToken, lpApplicationName
			, lpCommandLine, dwCreationFlags, lpStartupInfo, lpEnvironment
			, lpCurrentDirectory, &m_h, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

#if _WIN32_WINNT >= 0x0500

	HANDLE CreateWithLogon
		( __in        LPCWSTR        lpUsername
		, __in_opt    LPCWSTR        lpDomain
		, __in        LPCWSTR        lpPassword
		, __in        DWORD          dwLogonFlags
		, __in_opt    LPCWSTR        lpApplicationName
		, __inout_opt LPWSTR         lpCommandLine
		, __in        DWORD          dwCreationFlags
		, __in_opt    LPVOID         lpEnvironment
		, __in_opt    LPCWSTR        lpCurrentDirectory
		, __in        LPSTARTUPINFOW lpStartupInfo
		, __out_opt   LPHANDLE       lphThread    = NULL
		, __out_opt   LPDWORD        lpnProcessId = NULL
		, __out_opt   LPDWORD        lpnThreadId  = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		BOOL b;

		b = HTL::CreateProcessWithLogon(lpUsername, lpDomain, lpPassword
			, dwLogonFlags, lpApplicationName, lpCommandLine, dwCreationFlags
			, lpStartupInfo, lpEnvironment, lpCurrentDirectory, &m_h
			, lphThread, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE CreateWithToken
		( __in        HANDLE         hToken
		, __in        DWORD          dwLogonFlags
		, __in_opt    LPCWSTR        lpApplicationName
		, __inout_opt LPWSTR         lpCommandLine
		, __in        DWORD          dwCreationFlags
		, __in_opt    LPVOID         lpEnvironment
		, __in_opt    LPCWSTR        lpCurrentDirectory
		, __in        LPSTARTUPINFOW lpStartupInfo
		, __out_opt   LPHANDLE       lphThread    = NULL
		, __out_opt   LPDWORD        lpnProcessId = NULL
		, __out_opt   LPDWORD        lpnThreadId  = NULL
		)
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		BOOL b;

		b = HTL::CreateProcessWithToken(hToken, dwLogonFlags
			, lpApplicationName, lpCommandLine, dwCreationFlags, lpStartupInfo
			, lpEnvironment, lpCurrentDirectory, &m_h, lphThread
			, lpnProcessId, lpnThreadId);
		_ASSERTE(b);
		return m_h;
	}

#endif // _WIN32_WINNT >= 0x0500

	HANDLE Open
		( __in DWORD nProcessId
		, __in DWORD nDesiredAccess = PROCESS_ALL_ACCESS
		, __in BOOL  bInheritHandle = FALSE
		)
	{
		_ASSERTE(!IsValid());

		m_h = ::OpenProcess(nDesiredAccess, bInheritHandle, nProcessId);
		return m_h;
	}

	BOOL Terminate
		( __in UINT uExitCode = 0U
		) const
	{
		_ASSERTE(IsValid());

		return ::TerminateProcess(m_h, uExitCode);
	}

	BOOL FlushInstructionCache
		( __in_bcount_opt(dwSize) LPCVOID lpBaseAddress
		, __in                    SIZE_T  nSize
		) const
	{
		_ASSERTE(lpBaseAddress);
		_ASSERTE(IsValid());

		return ::FlushInstructionCache(m_h, lpBaseAddress, nSize);
	}
	
	HANDLE CreateRemoteThread
		( __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		) const
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(IsValid());

		return ::CreateRemoteThread(m_h, NULL, 0, lpStartAddress, lpParameter
			, dwCreationFlags, lpnThreadId);
	}

	HANDLE CreateRemoteThread
		( __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
		, __in      SIZE_T                 nStackSize
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		) const
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(IsValid());

		return ::CreateRemoteThread(m_h, lpThreadAttributes, nStackSize
			, lpStartAddress, lpParameter, dwCreationFlags, lpnThreadId);
	}

	HANDLE CreateRemoteThreadEx
		( __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in      SIZE_T                 nStartRoutineSize
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      SIZE_T                 nParameterSize = 0
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		, __out_opt LPVOID                *lplpCodeRemote = NULL
		) const
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(IsValid());

		return HTL::CreateRemoteThreadEx(m_h, NULL, 0, lpStartAddress
			, nStartRoutineSize, lpParameter, nParameterSize
			, dwCreationFlags, lpnThreadId, lplpCodeRemote);
	}

	HANDLE CreateRemoteThreadEx
		( __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
		, __in      SIZE_T                 nStackSize
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in      SIZE_T                 nStartRoutineSize
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      SIZE_T                 nParameterSize = 0
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		, __out_opt LPVOID                *lplpCodeRemote = NULL
		) const
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(IsValid());

		return HTL::CreateRemoteThread(m_h, lpThreadAttributes, nStackSize
			, lpStartAddress, nStartRoutineSize, lpParameter, nParameterSize
			, dwCreationFlags, lpnThreadId, lplpCodeRemote);
	}

	LPVOID VirtualAllocEx
		( __in_opt LPVOID lpAddress
		, __in     SIZE_T nSize
		, __in     DWORD  nAllocationType
		, __in     DWORD  nProtect
		) const
	{
		_ASSERTE(lpAddress);
		_ASSERTE(IsValid());

		return ::VirtualAllocEx(m_h, lpAddress, nSize, nAllocationType
			, nProtect);
	}

	LPVOID VirtualAllocEx
		( __in     SIZE_T nSize
		, __in     DWORD  nAllocationType
		, __in     DWORD  nProtect
		) const
	{
		_ASSERTE(lpAddress);
		_ASSERTE(IsValid());

		return ::VirtualAllocEx(m_h, NULL, nSize, nAllocationType, nProtect);
	}

	BOOL VirtualFreeEx
		( __in LPVOID lpAddress
		, __in SIZE_T nSize
		, __in DWORD  nFreeType
		) const
	{
		_ASSERTE(lpAddress);
		_ASSERTE(IsValid());

		return ::VirtualFreeEx(m_h, lpAddress, nSize, nFreeType);
	}

	BOOL VirtualProtectEx
		( __in  LPVOID lpAddress
		, __in  SIZE_T nSize
		, __in  DWORD  nNewProtect
		, __out PDWORD pnOldProtect
		) const
	{
		_ASSERTE(lpAddress);
		_ASSERTE(pnOldProtect);
		_ASSERTE(IsValid());

		return ::VirtualProtectEx(m_h, lpAddress, nSize, nNewProtect
			, pnOldProtect);
	}

	SIZE_T VirtualQueryEx
		( __in                                LPVOID                    lpAddress
		, __out_bcount_part(dwLength, return) PMEMORY_BASIC_INFORMATION lpBuffer
		, __in                                SIZE_T                    nLength
		) const
	{
		_ASSERTE(lpAddress);
		_ASSERTE(lpBuffer);
		_ASSERTE(IsValid());

		return ::VirtualQueryEx(m_h, lpAddress, lpBuffer, nLength);
	}

	BOOL ReadMemory
		( __in                       LPCVOID lpBaseAddress
		, __out_bcount_part(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer
		, __in                       SIZE_T  nSize
		, __out_opt                  SIZE_T *lpnNumberOfBytesRead = NULL
		) const
	{
		_ASSERTE(lpBaseAddress);
		_ASSERTE(lpBuffer);
		_ASSERTE(IsValid());

		return ::ReadProcessMemory(m_h, lpBaseAddress, lpBuffer, nSize
			, lpnNumberOfBytesRead);
	}

	BOOL WriteMemory
		( __in               LPVOID  lpBaseAddress
		, __in_bcount(nSize) LPCVOID lpBuffer
		, __in               SIZE_T  nSize
		, __out_opt          SIZE_T *lpnNumberOfBytesWritten = NULL
		) const
	{
		_ASSERTE(lpBaseAddress);
		_ASSERTE(lpBuffer);
		_ASSERTE(IsValid());

		return ::WriteProcessMemory(m_h, lpBaseAddress, lpBuffer, nSize
			, lpnNumberOfBytesWritten);
	}

	BOOL OpenToken
		( __in        DWORD   nDesiredAccess
		, __deref_out PHANDLE phTokenHandle
		) const
	{
		_ASSERTE(phTokenHandle);
		_ASSERTE(IsValid());

		return ::OpenProcessToken(m_h, nDesiredAccess, phTokenHandle);
	}

	HANDLE OpenToken
		( __in DWORD nDesiredAccess
		) const
	{
		_ASSERTE(IsValid());
		HANDLE hTokenHandle;

		return ::OpenProcessToken(m_h, nDesiredAccess, &hTokenHandle)?
			hTokenHandle: NULL;
	}

	BOOL GetAffinityMask
		( __out PDWORD_PTR lpnProcessAffinityMask
		, __out PDWORD_PTR lpnSystemAffinityMask
		) const
	{
		_ASSERTE(lpnProcessAffinityMask);
		_ASSERTE(lpnSystemAffinityMask);
		_ASSERTE(IsValid());

		return ::GetProcessAffinityMask(m_h, lpnProcessAffinityMask
			, lpnSystemAffinityMask);
	}

	BOOL SetAffinityMask
		( __in DWORD_PTR nProcessAffinityMask
		) const
	{
		_ASSERTE(IsValid());

		return ::SetProcessAffinityMask(m_h, nProcessAffinityMask);
	}

#if _WIN32_WINNT >= 0x0501

	BOOL GetHandleCount
		( __out PDWORD pnHandleCount
		) const
	{
		_ASSERTE(pnHandleCount);
		_ASSERTE(IsValid());

		return ::GetProcessHandleCount(m_h, pnHandleCount);
	}
		
	DWORD GetHandleCount() const
	{
		_ASSERTE(IsValid());
		DWORD nHandleCount;

		return ::GetProcessHandleCount(m_h, &nHandleCount)? nHandleCount: (DWORD)~0;
	}

#endif // _WIN32_WINNT >= 0x0501

	BOOL GetTimes
		( __out LPFILETIME lpCreationTime
		, __out LPFILETIME lpExitTime
		, __out LPFILETIME lpKernelTime
		, __out LPFILETIME lpUserTime
		) const
	{
		_ASSERTE(IsValid());

		return ::GetProcessTimes(m_h, lpCreationTime, lpExitTime
			, lpKernelTime, lpUserTime);
	}

	BOOL GetIoCounters
		( __out PIO_COUNTERS lpIoCounters
		) const
	{
		_ASSERTE(lpIoCounters);
		_ASSERTE(IsValid());

		return ::GetProcessIoCounters(m_h, lpIoCounters);
	}

	BOOL GetWorkingSetSize
		( __out PSIZE_T lpnMinimumWorkingSetSize
		, __out PSIZE_T lpnMaximumWorkingSetSize
		) const
	{
		_ASSERTE(IsValid());

		return ::GetProcessWorkingSetSize(m_h, lpnMinimumWorkingSetSize
			, lpnMaximumWorkingSetSize);
	}

	BOOL GetWorkingSetSizeEx
		( __out PSIZE_T lpnMinimumWorkingSetSize
		, __out PSIZE_T lpnMaximumWorkingSetSize
		, __out PDWORD  pnFlags
		) const
	{
		_ASSERTE(IsValid());

		return ::GetProcessWorkingSetSizeEx(m_h, lpnMinimumWorkingSetSize
			, lpnMaximumWorkingSetSize, pnFlags);
	}

	BOOL SetWorkingSetSize
		( __in SIZE_T nMinimumWorkingSetSize
		, __in SIZE_T nMaximumWorkingSetSize
		) const
	{
		_ASSERTE(IsValid());

		return ::SetProcessWorkingSetSize(m_h, nMinimumWorkingSetSize
			, nMaximumWorkingSetSize);
	}

	BOOL SetWorkingSetSizeEx
		( __in SIZE_T nMinimumWorkingSetSize
		, __in SIZE_T pnMaximumWorkingSetSize
		, __in DWORD  nFlags
		) const
	{
		_ASSERTE(IsValid());

		return ::SetProcessWorkingSetSizeEx(m_h, nMinimumWorkingSetSize
			, nMaximumWorkingSetSize, nFlags);
	}

	BOOL GetPriorityBoost
		( __out PBOOL pbDisablePriorityBoost
		) const
	{
		_ASSERTE(pbDisablePriorityBoost);
		_ASSERTE(IsValid());

		return ::GetProcessPriorityBoost(m_h, pbDisablePriorityBoost);
	}

	int GetPriorityBoost() const
	{
		_ASSERTE(IsValid());
		BOOL bDisablePriorityBoost;

		return ::GetProcessPriorityBoost(m_h, &bDisablePriorityBoost)?
			!!bDisablePriorityBoost: -1;
	}

	BOOL SetPriorityBoost
		( __in BOOL bDisablePriorityBoost
		) const
	{
		_ASSERTE(IsValid());

		return ::SetProcessPriorityBoost(m_h, bDisablePriorityBoost);
	}

	BOOL SetPriorityClass
		( __in DWORD nPriorityClas
		) const
	{
		_ASSERTE(IsValid());

		return ::SetPriorityClass(m_h, nPriorityClas);
	}

	DWORD GetPriorityClass() const
	{
		_ASSERTE(IsValid());

		return ::GetPriorityClass(m_h);
	}

	BOOL GetExitCode
		( __out PDWORD pnExitCode
		) const
	{
		_ASSERTE(pnExitCode);
		_ASSERTE(IsValid());

		return ::GetExitCodeProcess(m_h, pnExitCode);
	}

	DWORD GetExitCode () const
	{
		_ASSERTE(pnExitCode);
		_ASSERTE(IsValid());
		DWORD nExitCode;

		return ::GetExitCodeProcess(m_h, &nExitCode)? nExitCode: (DWORD)~0;
	}

	BOOL GetId() const
	{
		_ASSERTE(IsValid());

		return ::GetProcessId(m_h);
	}

#if _WIN32_WINNT >= 0x0600

	BOOL QueryCycleTime
		( __out PULONG64 pulCycleTime
		) const
	{
		_ASSERTE(pulCycleTime);
		_ASSERTE(IsValid());

		return ::QueryProcessCycleTime(m_h, pulCycleTime);
	}

	ULONG64 QueryCycleTime() const
	{
		_ASSERTE(IsValid());
		ULONG64 ulCycleTime;

		return ::QueryProcessCycleTime(m_h, &ulCycleTime)? ulCycleTime: (ULONG64)~0UL;
	}

#endif // _WIN32_WINNT >= 0x0600

#if _WIN32_WINNT >= 0x0501

	BOOL CheckRemoteDebuggerPresent
		( __out PBOOL pbDebuggerPresent
		) const
	{
		_ASSERTE(pbDebuggerPresent);
		_ASSERTE(IsValid());

		return ::CheckRemoteDebuggerPresent(m_h, pbDebuggerPresent);
	}

	int CheckRemoteDebuggerPresent() const
	{
		_ASSERTE(IsValid());
		BOOL bDebuggerPresent;

		return ::CheckRemoteDebuggerPresent(m_h, &bDebuggerPresent)?
			!!bDebuggerPresent: -1;
	}

#endif // _WIN32_WINNT >= 0x0501

	BOOL DebugBreak() const
	{
		_ASSERTE(IsValid());

		return ::DebugBreakProcess(m_h);
	}

	BOOL AssignToJobObject
		( __in HANDLE hJobObject
		) const
	{
		_ASSERTE(IsValidHandle(hJobObject));
		_ASSERTE(IsValid());

		return ::AssignProcessToJobObject(hJobObject, m_h);
	}

	BOOL IsInJobObject
		( __in  HANDLE hJobObject
		, __out PBOOL  pbResult
		) const
	{
		_ASSERTE(IsValidHandle(hJobObject));
		_ASSERTE(pbResult);
		_ASSERTE(IsValid());

		return ::IsProcessInJobObject(hJobObject, m_h, pbResult);
	}

	int IsInJobObject
		( __in HANDLE hJobObject
		) const
	{
		_ASSERTE(IsValidHandle(hJobObject));
		_ASSERTE(IsValid());
		BOOL bResult;

		if (::IsProcessInJobObject(hJobObject, m_h, &bResult))
			return !!bResult;
		return -1;
	}

// WinUser.h

#if WINVER >= 0x0500

	DWORD GetGuiResources
		( __in DWORD uiFlags
		) const
	{
		return ::GetGuiResources(m_h, uiFlags);
	}

	DWORD WaitForInputIdle
		( __in DWORD dwMilliseconds = INFINITE
		) const
	{
		return ::WaitForInputIdle(m_h, dwMilliseconds);
	}

#endif // WINVER >= 0x0500


	#pragma region Very Large Memory API Subset

#if _WIN32_WINNT >= 0x0500

	BOOL AllocateUserPhysicalPages
		( __inout PULONG_PTR pnNumberOfPages
		, __out_ecount_part(*NumberOfPages, *NumberOfPages)
		          PULONG_PTR pnPageArray
		) const
	{
		_ASSERTE(pnNumberOfPages);
		_ASSERTE(pnPageArray);
		_ASSERTE(IsValid());

		return ::AllocateUserPhysicalPages(m_h, pnNumberOfPages, pnPageArray);
	}

	BOOL FreeUserPhysicalPages
		( __inout                     PULONG_PTR NumberOfPages
		, __in_ecount(*NumberOfPages) PULONG_PTR PageArray
		) const
	{
		_ASSERTE(pnNumberOfPages);
		_ASSERTE(pnPageArray);
		_ASSERTE(IsValid());

		return ::FreeUserPhysicalPages(m_h, pnNumberOfPages, pnPageArray);
	}

	#pragma endregion

#endif // _WIN32_WINNT >= 0x0500

#if _WIN32_WINNT >= 0x0501

	BOOL IsWow64
		( __out PBOOL pbWow64Process
		) const
	{
		_ASSERTE(pbWow64Process);
		_ASSERTE(IsValid());

		return ::IsWow64Process(m_h, pbWow64Process);
	}

	int IsWow64() const
	{
		_ASSERTE(IsValid());
		BOOL bWow64Process;

		return ::IsWow64Process(m_h, &bWow64Process)? !!bWow64Process: -1;
	}

#endif // (_WIN32_WINNT >= 0x0501)

#pragma region PSAPI

#if defined(_PSAPI_H_)

	BOOL EmptyWorkingSet() const
	{
		_ASSERTE(IsValid());

		return ::EmptyWorkingSet(m_h);
	}

	BOOL EnumModules
		( __out_bcount(cb) HMODULE* lphModule
		, __in             DWORD    cb
		, __out            LPDWORD  lpcbNeeded
		) const
	{
		_ASSERTE(IsValid());

		return ::EnumProcessModules(m_h, lphModule, cb, lpcbNeeded);
	}

	BOOL EnumModulesEx
		( __out_bcount(cb) HMODULE* lphModule
		, __in             DWORD    cb
		, __out            LPDWORD  lpcbNeeded
		, __in             DWORD    dwFilterFlag
		) const
	{
		_ASSERTE(IsValid());

		return ::EnumProcessModulesEx(m_h, lphModule, cb, lpcbNeeded, dwFilterFlag);
	}

	DWORD GetModuleBaseName
		( __in_opt            HMODULE hModule
		, __out_ecount(nSize) LPSTR   lpBaseName
		, __in                DWORD   nSize
		) const
	{
		_ASSERTE(lpBaseName);
		_ASSERTE(IsValid());

		return ::GetModuleBaseNameA(m_h, hModule, lpBaseName, nSize);
	}

	DWORD GetModuleBaseName
		( __in_opt            HMODULE hModule
		, __out_ecount(nSize) LPWSTR  lpBaseName
		, __in                DWORD   nSize
		) const
	{
		_ASSERTE(lpBaseName);
		_ASSERTE(IsValid());

		return ::GetModuleBaseNameW(m_h, hModule, lpBaseName, nSize);
	}

	DWORD GetModuleFileNameEx
		( __in_opt            HMODULE hModule
		, __out_ecount(nSize) LPSTR   lpFilename
		, __in                DWORD   nSize
		) const
	{
		_ASSERTE(lpFilename);
		_ASSERTE(IsValid());

		return ::GetModuleFileNameExA(m_h, hModule, lpFilename, nSize);
	}

	DWORD GetModuleFileNameEx
		( __in_opt            HMODULE hModule
		, __out_ecount(nSize) LPWSTR  lpFilename
		, __in                DWORD   nSize
		) const
	{
		_ASSERTE(lpFilename);
		_ASSERTE(IsValid());

		return ::GetModuleFileNameExW(m_h, hModule, lpFilename, nSize);
	}

	BOOL GetModuleInformation
		( __in  HMODULE      hModule
		, __out LPMODULEINFO lpModInfo
		, __in  DWORD        cb
		) const
	{
		_ASSERTE(lpModInfo);
		_ASSERTE(IsValid());

		return ::GetModuleInformation(m_h, hModule, lpModInfo, cb);
	}

	BOOL QueryWorkingSet
		( __out_bcount(cb) PVOID pv
		, __in             DWORD cb
		) const
	{
		_ASSERTE(pv);
		_ASSERTE(IsValid());

		return ::QueryWorkingSet(m_h, pv, cb);
	}

	BOOL InitializeProcessForWsWatch() const
	{
		_ASSERTE(IsValid());

		return ::InitializeProcessForWsWatch(m_h);
	}

	BOOL GetWsChanges
		( __out_bcount(cb) PPSAPI_WS_WATCH_INFORMATION lpWatchInfo
		, __in             DWORD                       cb
		) const
	{
		_ASSERTE(lpWatchInfo);
		_ASSERTE(IsValid());

		return ::GetWsChanges(m_h, lpWatchInfo, cb);
	}

#if _WIN32_WINNT >= 0x0600

	BOOL GetWsChangesEx
		( __out_bcount_part(*cb, *cb) PPSAPI_WS_WATCH_INFORMATION_EX lpWatchInfoEx
		, __inout                     PDWORD                         cb
		) const
	{
		_ASSERTE(IsValid());

		return ::GetWsChangesEx(m_h, lpWatchInfoEx, cb);
	}

#endif // _WIN32_WINNT >= 0x0600

	DWORD GetMappedFileName
		( __in                LPVOID lpv
		, __out_ecount(nSize) LPSTR  lpFilename
		, __in                DWORD  nSize
		) const
	{
		_ASSERTE(lpv);
		_ASSERTE(IsValid());

		return ::GetMappedFileNameA(m_h, lpv, lpFilename, nSize);
	}

	DWORD GetMappedFileName
		( __in                LPVOID lpv
		, __out_ecount(nSize) LPWSTR lpFilename
		, __in                DWORD  nSize
		) const
	{
		_ASSERTE(lpv);
		_ASSERTE(IsValid());

		return ::GetMappedFileNameW(m_h, lpv, lpFilename, nSize);
	}

#if _WIN32_WINNT >= 0x0501

	DWORD GetImageFileName
		( __out_ecount(nSize) LPSTR lpImageFileName
		, __in                DWORD nSize
		) const
	{
		_ASSERTE(IsValid());

		return ::GetProcessImageFileNameA(m_h, lpImageFileName, nSize);
	}

	DWORD GetImageFileName
		( __out_ecount(nSize) LPWSTR lpImageFileName
		, __in                DWORD  nSize
		) const
	{
		_ASSERTE(IsValid());

		return ::GetProcessImageFileNameW(m_h, lpImageFileName, nSize);
	}

#endif // _WIN32_WINNT >= 0x0501

#if _WIN32_WINNT >= 0x0502

	BOOL QueryWorkingSetEx
		( __out_bcount(cb) PVOID pv
		, __in             DWORD cb
		) const
	{
		_ASSERTE(pv);
		_ASSERTE(IsValid());

		return ::QueryWorkingSetEx(m_h, pv, cb);
	}

#endif // _WIN32_WINNT >= 0x0502

#endif // defined(_PSAPI_H_)

#pragma endregion

};

typedef CProcessT<true>  CProcess;
typedef CProcessT<false> CProcessHandle;

class CCurrentProcessHandle
	: public CProcessHandle
{
public:
	CCurrentProcessHandle()
		: CProcessHandle(::GetCurrentProcess())
	{ }
};

/////////////////////////////////////////////////////////////////////////////
// Thread

template<bool t_bManaged>
class CThreadT
	: public CHandleT<t_bManaged>
{
	typedef CHandleT<t_bManaged> Base;
public:
	CThreadT()
	{ }
	CThreadT
		( __in const CThreadT<true>& rThread
		)
		: Base(rThread)
	{ }
	CThreadT
		( __in const CThreadT<false>& rThread
		)
		: Base(rThread)
	{ }
	explicit CThreadT
		( __in HANDLE hThread
		)
		: Base(hThread)
	{ }

	explicit CThreadT
		( __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		Create(lpStartAddress, lpParameter, dwCreationFlags, lpnThreadId);
		_ASSERTE(IsValid());
	}

	CThreadT
		( __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
		, __in      SIZE_T                 nStackSize
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		Create(lpThreadAttributes, nStackSize, lpStartAddress, lpParameter
			, dwCreationFlags, lpnThreadId);
		_ASSERTE(IsValid());
	}

	CThreadT
		( __in DWORD nThreadId
		, __in DWORD nDesiredAccess
		, __in BOOL  bInheritHandle = FALSE
		)
	{
		Open(nThreadId, nDesiredAccess, bInheritHandle);
		_ASSERTE(IsValid());
	}

	CThreadT<t_bManaged>& operator=
		( __in HANDLE h
		)
	{
		Base::operator=(h);
		return *this;
	}

	CThreadT<t_bManaged>& operator=
		( __in const CThreadT<true>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	CThreadT<t_bManaged>& operator=
		( __in const CThreadT<false>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	bool IsValid() const
	{
		return HTL::IsValidThread(m_h);
	}

	HANDLE Create
		( __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
		, __in      SIZE_T                 nStackSize
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(!IsValid());
		DWORD nThreadId;

		if (lpnThreadId == NULL)
			lpnThreadId = &nThreadId;

		m_h = ::CreateThread(lpThreadAttributes, nStackSize, lpStartAddress
			, lpParameter, dwCreationFlags, lpnThreadId);
		return m_h;
	}

	HANDLE Create
		( __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(!IsValid());
		DWORD nThreadId;

		if (lpnThreadId == NULL)
			lpnThreadId = &nThreadId;

		m_h = ::CreateThread(NULL, 0, lpStartAddress, lpParameter
			, dwCreationFlags, lpnThreadId);
		return m_h;
	}

	HANDLE CreateRemote
		( __in      HANDLE                 hProcess
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(!IsValid());

		m_h = ::CreateRemoteThread(hProcess, NULL, 0, lpStartAddress
			, lpParameter, dwCreationFlags, lpnThreadId);
		return m_h;
	}

	HANDLE CreateRemote
		( __in      HANDLE                 hProcess
		, __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
		, __in      SIZE_T                 nStackSize
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(!IsValid());

		m_h = ::CreateRemoteThread(hProcess, lpThreadAttributes, nStackSize
			, lpStartAddress, lpParameter, dwCreationFlags, lpnThreadId);
		return m_h;
	}

	HANDLE CreateRemoteEx
		( __in      HANDLE                 hProcess
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in      SIZE_T                 nStartRoutineSize
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      SIZE_T                 nParameterSize = 0
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(!IsValid());

		m_h = HTL::CreateRemoteThreadEx(hProcess, NULL, 0, lpStartAddress
			, nStartRoutineSize, lpParameter, nParameterSize, dwCreationFlags
			, lpnThreadId);
		return m_h;
	}

	HANDLE CreateRemoteEx
		( __in      HANDLE                 hProcess
		, __in_opt  LPSECURITY_ATTRIBUTES  lpThreadAttributes
		, __in      SIZE_T                 nStackSize
		, __in      LPTHREAD_START_ROUTINE lpStartAddress
		, __in      SIZE_T                 nStartRoutineSize
		, __in_opt  LPVOID                 lpParameter    = NULL
		, __in      SIZE_T                 nParameterSize = 0
		, __in      DWORD                  dwCreationFlags = 0
		, __out_opt LPDWORD                lpnThreadId    = NULL
		)
	{
		_ASSERTE(lpStartAddress);
		_ASSERTE(!IsValid());

		m_h = HTL::CreateRemoteThreadEx(hProcess, lpThreadAttributes
			, nStackSize, lpStartAddress, nStartRoutineSize, lpParameter
			, nParameterSize, dwCreationFlags, lpnThreadId);
		return m_h;
	}

	HANDLE Open
		( __in DWORD nThreadId
		, __in DWORD nDesiredAccess = THREAD_ALL_ACCESS
		, __in BOOL  bInheritHandle = FALSE
		)
	{
		_ASSERTE(!IsValid());

		m_h = ::OpenThread(nDesiredAccess, bInheritHandle, nThreadId);
		return m_h;
	}

	BOOL Terminate
		( __in UINT uExitCode = 0U
		) const
	{
		_ASSERTE(IsValid());

		return ::TerminateThread(m_h, uExitCode);
	}

#if _WIN32_WINNT >= 0x0600

	BOOL CancelSynchronousIo() const
	{
		_ASSERTE(IsValid());

		return ::CancelSynchronousIo(m_h);
	}

#endif // _WIN32_WINNT >= 0x0600

	DWORD GetId() const
	{
		_ASSERTE(IsValid());

		return ::GetThreadId(m_h);
	}

	DWORD GetProcessId() const
	{
		_ASSERTE(IsValid());

		return ::GetProcessIdOfThread(m_h);
	}

	DWORD_PTR SetAffinityMask
		( __in DWORD_PTR nThreadAffinityMask
		) const
	{
		_ASSERTE(IsValid());

		return ::SetThreadAffinityMask(m_h, nThreadAffinityMask);
	}

#if _WIN32_WINNT >= 0x0400
	DWORD SetIdealProcessor
		( __in DWORD nIdealProcessor
		) const
	{
		_ASSERTE(IsValid());

		return ::SetThreadIdealProcessor(m_h, nIdealProcessor);
	}
#endif // _WIN32_WINNT >= 0x0400

	BOOL SetPriority
		( __in int nPriority
		) const
	{
		_ASSERTE(IsValid());

		return ::SetThreadPriority(m_h, nPriority);
	}

	int GetPriority() const
	{
		_ASSERTE(IsValid());

		return ::GetThreadPriority(m_h);
	}

	BOOL SetPriorityBoost
		( __in BOOL bDisablePriorityBoost
		) const
	{
		_ASSERTE(IsValid());

		return ::SetThreadPriorityBoost(m_h, bDisablePriorityBoost);
	}

	BOOL GetPriorityBoost
		( __out PBOOL pbDisablePriorityBoost
		) const
	{
		_ASSERTE(pbDisablePriorityBoost);
		_ASSERTE(IsValid());

		return ::GetThreadPriorityBoost(m_h, pbDisablePriorityBoost);
	}

	int GetPriorityBoost() const
	{
		_ASSERTE(IsValid());
		BOOL bDisablePriorityBoost;

		if (::GetThreadPriorityBoost(m_h, &bDisablePriorityBoost))
			return !!bDisablePriorityBoost;
		return -1;
	}

	BOOL GetTimes
		( __out LPFILETIME lpCreationTime
		, __out LPFILETIME lpExitTime
		, __out LPFILETIME lpKernelTime
		, __out LPFILETIME lpUserTime
		) const
	{
		_ASSERTE(IsValid());

		return ::GetThreadTimes(m_h, lpCreationTime, lpExitTime
			, lpKernelTime, lpUserTime);
	}

#if _WIN32_WINNT >= 0x0501

	BOOL GetIOPendingFlag
		( __out PBOOL pbIOIsPending
		) const
	{
		_ASSERTE(pbIOIsPending);
		_ASSERTE(IsValid());

		return ::GetThreadIOPendingFlag(m_h, pbIOIsPending);
	}

	int GetIOPendingFlag() const
	{
		_ASSERTE(IsValid());
		BOOL bIOIsPending;

		return ::GetThreadIOPendingFlag(m_h, &bIOIsPending)? !!bIOIsPending: -1;
	}

#endif // _WIN32_WINNT >= 0x0501

	BOOL GetExitCode
		( __out PDWORD pnExitCode
		) const
	{
		_ASSERTE(pnExitCode);
		_ASSERTE(IsValid());

		return ::GetExitCodeThread(m_h, pnExitCode);
	}

	BOOL GetSelectorEntry
		( __in  DWORD       nSelector
		, __out LPLDT_ENTRY lpSelectorEntry
		) const
	{
		_ASSERTE(lpSelectorEntry);
		_ASSERTE(IsValid());

		return ::GetThreadSelectorEntry(m_h, nSelector, lpSelectorEntry);
	}

	BOOL GetContext
		( __inout LPCONTEXT lpContext
		) const
	{
		_ASSERTE(lpContext);
		_ASSERTE(IsValid());

		return ::GetThreadContext(m_h, lpContext);
	}

	BOOL SetContext
		( __in CONST CONTEXT *lpContext
		) const
	{
		_ASSERTE(lpContext);
		_ASSERTE(IsValid());

		return ::SetThreadContext(m_h, lpContext);
	}

	DWORD Suspend() const
	{
		_ASSERTE(IsValid());

		return ::SuspendThread(m_h);
	}

	DWORD Resume() const
	{
		_ASSERTE(IsValid());

		return ::ResumeThread(m_h);
	}

#if _WIN32_WINNT >= 0x0600

	BOOL QueryCycleTime
		( __out PULONG64 pulCycleTime
		) const
	{
		_ASSERTE(pulCycleTime);
		_ASSERTE(IsValid());

		return ::QueryThreadCycleTime(m_h, pulCycleTime);
	}

	ULONG64 QueryCycleTime() const
	{
		_ASSERTE(IsValid());
		ULONG64 ulCycleTime;

		return ::QueryThreadCycleTime(m_h, &ulCycleTime)? ulCycleTime: (ULONG64)~0UL;
	}

#endif // _WIN32_WINNT >= 0x0600

#if _WIN32_WINNT >= 0x0400 || _WIN32_WINDOWS > 0x0400

	DWORD QueueUserAPC
		( __in PAPCFUNC  pfnAPC
		, __in ULONG_PTR pData = 0UL
		) const
	{
		_ASSERTE(pfnAPC);
		_ASSERTE(IsValid());

		return ::QueueUserAPC(pfnAPC, m_h, pData);
	}

#endif // _WIN32_WINNT >= 0x0400 || _WIN32_WINDOWS > 0x0400

	BOOL SetToken
		( __in_opt HANDLE hToken = NULL
		) const
	{
		_ASSERTE(IsValid());

		return ::SetThreadToken(&m_h, hToken);
	}

	BOOL OpenToken
		( __in        DWORD   nDesiredAccess
		, __in        BOOL    bOpenAsSelf
		, __deref_out PHANDLE phTokenHandle
		) const
	{
		_ASSERTE(phTokenHandle);
		_ASSERTE(IsValid());

		return ::OpenThreadToken(m_h, nDesiredAccess, bOpenAsSelf
			, phTokenHandle);
	}

	BOOL ImpersonateAnonymousToken() const
	{
		_ASSERTE(IsValid());

		return ::ImpersonateAnonymousToken(m_h);
	}
};

typedef CThreadT<true>  CThread;
typedef CThreadT<false> CThreadHandle;

class CCurrentThreadHandle
	: public CThreadHandle
{
public:
	CCurrentThreadHandle()
		: CThreadHandle(::GetCurrentThread())
	{ }
};


/////////////////////////////////////////////////////////////////////////////
// JobObject

template<bool t_bManaged>
class CJobObjectT
	: public CHandleT<t_bManaged>
{
	typedef CHandleT<t_bManaged> Base;
public:
	using HTL::CHandleT<t_bManaged>::SetInformation;

	CJobObjectT()
	{ }
	CJobObjectT
		( __in const CJobObjectT<true>& rJobObject
		)
		: Base(rJobObject)
	{ }
	CJobObjectT
		( __in const CJobObjectT<false>& rJobObject
		)
		: Base(rJobObject)
	{ }
	explicit CJobObjectT
		( __in HANDLE hJobObject
		)
		: Base(hJobObject)
	{ }

	explicit CJobObjectT
		( __in     LPCSTR                lpName
		, __in_opt LPSECURITY_ATTRIBUTES lpJobObjectAttributes = NULL
		)
	{
		Create(lpName, lpJobObjectAttributes);
		_ASSERTE(IsValid());
	}

	explicit CJobObjectT
		( __in     LPCWSTR               lpName
		, __in_opt LPSECURITY_ATTRIBUTES lpJobObjectAttributes = NULL
		)
	{
		Create(lpName, lpJobObjectAttributes);
		_ASSERTE(IsValid());
	}

	CJobObjectT
		( __in LPCSTR lpName
		, __in DWORD  nDesiredAccess
		, __in BOOL   bInheritHandle = FALSE
		)
	{
		Open(lpName, nDesiredAccess, bInheritHandle);
		_ASSERTE(IsValid());
	}

	CJobObjectT
		( __in LPCWSTR lpName
		, __in DWORD   nDesiredAccess
		, __in BOOL    bInheritHandle = FALSE
		)
	{
		Open(lpName, nDesiredAccess, bInheritHandle);
		_ASSERTE(IsValid());
	}

	CJobObjectT<t_bManaged>& operator=
		( __in HANDLE h
		)
	{
		Base::operator=(h);
		return *this;
	}

	CJobObjectT<t_bManaged>& operator=
		( __in const CJobObjectT<true>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	CJobObjectT<t_bManaged>& operator=
		( __in const CJobObjectT<false>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	HANDLE Create
		( __in     LPCSTR                lpName
		, __in_opt LPSECURITY_ATTRIBUTES lpJobObjectAttributes = NULL
		)
	{
		_ASSERTE(!IsValid());

		m_h = ::CreateJobObject(lpJobObjectAttributes, lpName);
		return m_h;
	}

	HANDLE Create
		( __in     LPCWSTR               lpName
		, __in_opt LPSECURITY_ATTRIBUTES lpJobObjectAttributes = NULL
		)
	{
		_ASSERTE(!IsValid());

		m_h = ::CreateJobObject(lpJobObjectAttributes, lpName);
		return m_h;
	}

	HANDLE Open
		( __in LPCSTR lpName
		, __in DWORD  nDesiredAccess = JOB_ALL_ACCESS
		, __in BOOL   bInheritHandle = FALSE
		)
	{
		_ASSERTE(!IsValid());

		m_h = ::OpenJobObject(nDesiredAccess, bInheritHandle, lpName);
		return m_h;
	}

	HANDLE Open
		( __in LPCWSTR lpName
		, __in DWORD   nDesiredAccess = JOB_ALL_ACCESS
		, __in BOOL    bInheritHandle = FALSE
		)
	{
		_ASSERTE(!IsValid());

		m_h = ::OpenJobObject(nDesiredAccess, bInheritHandle, lpName);
		return m_h;
	}

	BOOL AssignProcess
		( __in HANDLE hProcess
		) const
	{
		_ASSERTE(IsValidProcess(hProcess));
		_ASSERTE(IsValid());

		return ::AssignProcessToJobObject(m_h, hProcess);
	}

	BOOL Terminate
		( __in UINT uExitCode = 0U
		) const
	{
		_ASSERTE(IsValid());

		return ::TerminateJobObject(m_h, uExitCode);
	}

	BOOL QueryInformation
		( __in      JOBOBJECTINFOCLASS JobObjectInformationClass
		, __out_bcount_part(cbJobObjectInformationLength, *lpReturnLength)
		            LPVOID             lpJobObjectInformation
		, __in      DWORD              cbJobObjectInformationLength
		, __out_opt LPDWORD            lpReturnLength
		) const
	{
		_ASSERTE(JobObjectBasicAccountingInformation 
			<= JobObjectInformationClass);
		_ASSERTE(MaxJobObjectInfoClass 
			>= JobObjectInformationClass);
		_ASSERTE(IsValid());

		return ::QueryInformationJobObject(m_h, JobObjectInformationClass
			, lpJobObjectInformation, nJobObjectInformationLength
			, lpnReturnLength);
	}

	BOOL SetInformation
		( __in JOBOBJECTINFOCLASS JobObjectInformationClass
		, __in_bcount(cbJobObjectInformationLength)
		       LPVOID             lpJobObjectInformation
		, __in DWORD              cbJobObjectInformationLength
		) const
	{
		_ASSERTE(JobObjectBasicAccountingInformation 
			<= JobObjectInformationClass);
		_ASSERTE(MaxJobObjectInfoClass 
			>= JobObjectInformationClass);
		_ASSERTE(IsValid());

		return ::SetInformationJobObject(m_h, JobObjectInformationClass
			, lpJobObjectInformation, nJobObjectInformationLength);
	}

	BOOL IsProcessInJob
		( __in  HANDLE hProcess
		, __out PBOOL  pbResult
		) const
	{
		_ASSERTE(pbResult);
		_ASSERTE(IsValid());

		return ::IsProcessInJob(hProcess, m_h, pbResult);
	}

	int IsProcessInJob
		( __in HANDLE hProcess
		) const
	{
		_ASSERTE(IsValid());
		BOOL bResult;

		return ::IsProcessInJob(hProcess, m_h, &bResult)? !!bResult: -1;
	}

};

typedef CJobObjectT<true>  CJobObject;
typedef CJobObjectT<false> CJobObjectHandle;

/////////////////////////////////////////////////////////////////////////////
// Token

template<bool t_bManaged>
class CTokenT
	: public CHandleT<t_bManaged>
{
	typedef CHandleT<t_bManaged> Base;
public:
	using HTL::CHandleT<t_bManaged>::DuplicateTo;
	using HTL::CHandleT<t_bManaged>::DuplicateFrom;
	using HTL::CHandleT<t_bManaged>::GetInformation;
	using HTL::CHandleT<t_bManaged>::SetInformation;

	CTokenT()
	{ }
	CTokenT
		( __in const CTokenT<true>& rToken
		)
		: Base(rToken)
	{ }
	CTokenT
		( __in const CTokenT<false>& rToken
		)
		: Base(rToken)
	{ }
	explicit CTokenT
		( __in HANDLE hToken
		)
		: Base(hToken)
	{ }

	CTokenT<t_bManaged>& operator=
		( __in HANDLE h
		)
	{
		Base::operator=(h);
		return *this;
	}

	CTokenT<t_bManaged>& operator=
		( __in const CTokenT<true>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	CTokenT<t_bManaged>& operator=
		( __in const CTokenT<false>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	HANDLE LogonUser
		( __in     LPCSTR lpszUsername
		, __in_opt LPCSTR lpszDomain
		, __in     LPCSTR lpszPassword
		, __in     DWORD  dwLogonType
		, __in     DWORD  dwLogonProvider
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::LogonUserA(lpszUsername, lpszDomain, lpszPassword, nLogonType
			, nLogonProvider, &m_h);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE LogonUser
		( __in     LPCWSTR lpszUsername
		, __in_opt LPCWSTR lpszDomain
		, __in     LPCWSTR lpszPassword
		, __in     DWORD   dwLogonType
		, __in     DWORD   dwLogonProvider
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::LogonUserW(lpszUsername, lpszDomain, lpszPassword, nLogonType
			, nLogonProvider, &m_h);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE LogonUserEx
		( __in            LPCSTR        lpszUsername
		, __in_opt        LPCSTR        lpszDomain
		, __in            LPCSTR        lpszPassword
		, __in            DWORD         dwLogonType
		, __in            DWORD         dwLogonProvider
		, __deref_opt_out PSID         *ppLogonSid       = NULL
		, __deref_opt_out_bcount_full(*pdwProfileLength)
		                  PVOID        *ppProfileBuffer  = NULL
		, __out_opt       LPDWORD       pdwProfileLength = NULL
		, __out_opt       PQUOTA_LIMITS pQuotaLimits     = NULL
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::LogonUserExA(lpszUsername, lpszDomain, lpszPassword, nLogonType
			, nLogonProvider, &m_h, ppLogonSid, ppProfileBuffer
			, pnProfileLength, pQuotaLimits);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE LogonUserEx
		( __in            LPCWSTR       lpszUsername
		, __in_opt        LPCWSTR       lpszDomain
		, __in            LPCWSTR       lpszPassword
		, __in            DWORD         dwLogonType
		, __in            DWORD         dwLogonProvider
		, __deref_opt_out PSID         *ppLogonSid       = NULL
		, __deref_opt_out_bcount_full(*pdwProfileLength)
		                  PVOID        *ppProfileBuffer  = NULL
		, __out_opt       LPDWORD       pdwProfileLength = NULL
		, __out_opt       PQUOTA_LIMITS pQuotaLimits     = NULL
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::LogonUserExW(lpszUsername, lpszDomain, lpszPassword, nLogonType
			, nLogonProvider, &m_h, ppLogonSid, ppProfileBuffer
			, pnProfileLength, pQuotaLimits);
		_ASSERTE(b);
		return m_h;
	}

	HANDLE OpenProcess
		( __in HANDLE hProcessHandle
		, __in DWORD  nDesiredAccess
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::OpenProcessToken(hProcessHandle, nDesiredAccess, &m_h);
		ATLASSERT(b);
		return m_h;
	}

	HANDLE OpenThread
		( __in HANDLE hThreadHandle
		, __in DWORD  nDesiredAccess
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::OpenThreadToken(hThreadHandle, nDesiredAccess, &m_h);
		ATLASSERT(b);
		return m_h;
	}

	HANDLE CreateRestricted
		( __in HANDLE               hExistingTokenHandle
		, __in DWORD                nFlags
		, __in DWORD                nDisableSidCount      = 0
		, __in_ecount_opt(DisableSidCount)
		       PSID_AND_ATTRIBUTES  pSidsToDisable        = NULL
		, __in DWORD                nDeletePrivilegeCount = 0
		, __in_ecount_opt(DeletePrivilegeCount)
		       PLUID_AND_ATTRIBUTES pPrivilegesToDelete   = NULL
		, __in DWORD                nRestrictedSidCount   = 0
		, __in_ecount_opt(RestrictedSidCount)
		       PSID_AND_ATTRIBUTES  pSidsToRestrict       = NULL
		)
	{
		_ASSERTE(!IsValid());
		BOOL b;

		b = ::CreateRestrictedToken(hExistingTokenHandle, nFlags
			, nDisableSidCount, pSidsToDisable, nDeletePrivilegeCount
			, pPrivilegesToDelete, nRestrictedSidCount
			, pSidsToRestrict, &m_h);
		ATLASSERT(b);
		return m_h;
	}

	BOOL CreateRestricted
		( __in  DWORD                nFlags
		, __out PHANDLE              phNewTokenHandle
		, __in  DWORD                nDisableSidCount      = 0
		, __in_ecount_opt(DisableSidCount)
		        PSID_AND_ATTRIBUTES  pSidsToDisable        = NULL
		, __in  DWORD                nDeletePrivilegeCount = 0
		, __in_ecount_opt(DeletePrivilegeCount)
		        PLUID_AND_ATTRIBUTES pPrivilegesToDelete   = NULL
		, __in  DWORD                nRestrictedSidCount   = 0
		, __in_ecount_opt(RestrictedSidCount)
		        PSID_AND_ATTRIBUTES  pSidsToRestrict       = NULL
		)
	{
		_ASSERTE(IsValid());
		
		return ::CreateRestrictedToken(m_h, nFlags, nDisableSidCount
			, pSidsToDisable, nDeletePrivilegeCount, pPrivilegesToDelete
			, nRestrictedSidCount, pSidsToRestrict, phNewTokenHandle);
	}

	BOOL IsRestricted() const
	{
		_ASSERTE(IsValid());

		return ::IsTokenRestricted(m_h);
	}

	BOOL IsUntrusted() const
	{
		_ASSERTE(IsValid());

		return ::IsTokenUntrusted(m_h);
	}

	BOOL DuplicateFrom
		( __in HANDLE                       hSource
		, __in SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
		)
	{
		_ASSERTE(IsValidHandle(hSource));
		_ASSERTE(!IsValid());

		return ::DuplicateToken(hSource, ImpersonationLevel, &m_h);
	}

	BOOL DuplicateFrom
		( __in     HANDLE                       hSource
		, __in     DWORD                        nDesiredAccess
		, __in_opt LPSECURITY_ATTRIBUTES        lpTokenAttributes
		, __in     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
		, __in     TOKEN_TYPE                   TokenType
		)
	{
		_ASSERTE(IsValidHandle(hSource));
		_ASSERTE(!IsValid());

		return ::DuplicateTokenEx(hSource, nDesiredAccess, lpTokenAttributes
			, ImpersonationLevel, TokenType, &m_h);
	}

	BOOL DuplicateTo
		( __out LPHANDLE                     lphDest
		, __in  SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
		) const
	{
		_ASSERTE(lphDest);
		_ASSERTE(IsValid());

		return ::DuplicateToken(m_h, ImpersonationLevel, lphDest);
	}

	BOOL DuplicateTo
		( __in     DWORD                        nDesiredAccess
		, __in_opt LPSECURITY_ATTRIBUTES        lpTokenAttributes
		, __in     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
		, __in     TOKEN_TYPE                   TokenType
		, __out    LPHANDLE                     lphDest
		) const
	{
		_ASSERTE(lphDest);
		_ASSERTE(IsValid());

		return ::DuplicateTokenEx(m_h, nDesiredAccess, lpTokenAttributes
			, ImpersonationLevel, TokenType, lphDest);
	}

	BOOL ImpersonateLoggedOnUser() const
	{
		_ASSERTE(IsValid());

		return ::ImpersonateLoggedOnUser(m_h);
	}

	BOOL SetThread
		( __in_opt PHANDLE phThread
		) const
	{
		return ::SetThreadToken(phThread, m_h);
	}

	BOOL GetInformation
		( __in  TOKEN_INFORMATION_CLASS TokenInformationClass
		, __out_bcount_part_opt(nTokenInformationLength, *pnReturnLength)
		        LPVOID                  lpTokenInformation
		, __in  DWORD                   nTokenInformationLength
		, __out PDWORD                  pnReturnLength
		) const
	{
		_ASSERTE(IsValid());

		return ::GetTokenInformation(m_h, TokenInformationClass
			, lpTokenInformation, nTokenInformationLength, pnReturnLength);
	}

	BOOL SetInformation
		( __in TOKEN_INFORMATION_CLASS TokenInformationClass
		, __in LPVOID                  lpTokenInformation
		, __in DWORD                   nTokenInformationLength
		) const
	{
		_ASSERTE(IsValid());

		return ::SetTokenInformation(m_h, TokenInformationClass
			, lpTokenInformation, nTokenInformationLength);
	}

	BOOL CreateProcessAsUser
		( __in      LPCSTR                lpApplicationName
		, __in_opt  LPSTR                 lpCommandLine       = NULL
		, __in_opt  LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL
		, __in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes  = NULL
		, __in      BOOL                  bInheritHandles     = FALSE
		, __in      DWORD                 dwCreationFlags     = 0
		, __in_opt  LPSTARTUPINFOA        lpStartupInfo       = NULL
		, __in_opt  LPVOID                lpEnvironment       = NULL
		, __in_opt  LPCSTR                lpCurrentDirectory  = NULL
		, __out_opt LPHANDLE              lphProcess          = NULL
		, __out_opt LPHANDLE              lphThread           = NULL
		, __out_opt LPDWORD               lpnProcessId        = NULL
		, __out_opt LPDWORD               lpnThreadId         = NULL
		) const
	{
		_ASSERTE(lpStartupInfo);
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(IsValid());

		return HTL::CreateProcessAsUser(m_h, lpApplicationName
			, lpCommandLine, lpProcessAttributes, lpThreadAttributes
			, bInheritHandles, dwCreationFlags, lpEnvironment
			, lpCurrentDirectory, lpStartupInfo, lphProcess, lphThread
			, lpnProcessId, lpnThreadId);
	}

	BOOL CreateProcessAsUser
		( __in      LPCWSTR               lpApplicationName
		, __in_opt  LPWSTR                lpCommandLine       = NULL
		, __in_opt  LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL
		, __in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes  = NULL
		, __in      BOOL                  bInheritHandles     = FALSE
		, __in      DWORD                 dwCreationFlags     = 0
		, __in_opt  LPSTARTUPINFOW        lpStartupInfo       = NULL
		, __in_opt  LPVOID                lpEnvironment       = NULL
		, __in_opt  LPCWSTR               lpCurrentDirectory  = NULL
		, __out_opt LPHANDLE              lphProcess          = NULL
		, __out_opt LPHANDLE              lphThread           = NULL
		, __out_opt LPDWORD               lpnProcessId        = NULL
		, __out_opt LPDWORD               lpnThreadId         = NULL
		) const
	{
		_ASSERTE(lpStartupInfo);
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(IsValid());

		return HTL::CreateProcessAsUser(m_h, lpApplicationName
			, lpCommandLine, lpProcessAttributes, lpThreadAttributes
			, bInheritHandles, dwCreationFlags, lpEnvironment
			, lpCurrentDirectory, lpStartupInfo, lphProcess, lphThread
			, lpnProcessId, lpnThreadId);
	}

	BOOL CreateProcessAsUser
		( __in      LPCSTR         lpApplicationName
		, __in_opt  LPSTR          lpCommandLine       = NULL
		, __in      DWORD          dwCreationFlags     = 0
		, __in_opt  LPSTARTUPINFOA lpStartupInfo       = NULL
		, __in_opt  LPVOID         lpEnvironment       = NULL
		, __in_opt  LPCSTR         lpCurrentDirectory  = NULL
		, __out_opt LPHANDLE       lphProcess          = NULL
		, __out_opt LPHANDLE       lphThread           = NULL
		, __out_opt LPDWORD        lpnProcessId        = NULL
		, __out_opt LPDWORD        lpnThreadId         = NULL
		) const
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(IsValid());
		
		return HTL::CreateProcessAsUser(m_h, lpApplicationName
			, lpCommandLine, dwCreationFlags, lpStartupInfo, lpEnvironment
			, lpCurrentDirectory, lphProcess, lphThread, lpnProcessId
			, lpnThreadId);
	}

	BOOL CreateProcessAsUser
		( __in      LPCWSTR        lpApplicationName
		, __in_opt  LPWSTR         lpCommandLine       = NULL
		, __in      DWORD          dwCreationFlags     = 0
		, __in_opt  LPSTARTUPINFOW lpStartupInfo       = NULL
		, __in_opt  LPVOID         lpEnvironment       = NULL
		, __in_opt  LPCWSTR        lpCurrentDirectory  = NULL
		, __out_opt LPHANDLE       lphProcess          = NULL
		, __out_opt LPHANDLE       lphThread           = NULL
		, __out_opt LPDWORD        lpnProcessId        = NULL
		, __out_opt LPDWORD        lpnThreadId         = NULL
		) const
	{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(IsValid());
		
		return HTL::CreateProcessAsUser(m_h, lpApplicationName
			, lpCommandLine, dwCreationFlags, lpStartupInfo, lpEnvironment
			, lpCurrentDirectory, lphProcess, lphThread, lpnProcessId
			, lpnThreadId);
	}

	BOOL AccessCheck
		( __in    PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in    DWORD                nDesiredAccess
		, __in    PGENERIC_MAPPING     pGenericMapping
		, __out_bcount_part_opt(*lpnPrivilegeSetLength, *lpnPrivilegeSetLength)
		          PPRIVILEGE_SET       pPrivilegeSet
		, __inout LPDWORD              lpnPrivilegeSetLength
		, __out   LPDWORD              lpnGrantedAccess
		, __out   LPBOOL               lpbAccessStatus
		) const
	{
		_ASSERTE(IsValid());

		return ::AccessCheck(pSecurityDescriptor, m_h, nDesiredAccess
			, pGenericMapping, pPrivilegeSet, lpnPrivilegeSetLength
			, lpnGrantedAccess, lpbAccessStatus);
	}

	BOOL AdjustPrivileges
		( __in      BOOL   bDisableAllPrivileges
		, __in_opt PTOKEN_PRIVILEGES pNewState       = NULL
		, __in      DWORD  nBufferLength             = 0
		, __out_bcount_part_opt(nBufferLength, *pnReturnLength)
		            PTOKEN_PRIVILEGES pPreviousState = NULL
		, __out_opt PDWORD pnReturnLength            = NULL
		) const
	{
		_ASSERTE(IsValid());

		return ::AdjustTokenPrivileges(m_h, bDisableAllPrivileges, pNewState
			, nBufferLength, pPreviousState, pnReturnLength);
	}

	BOOL AdjustGroups
		( __in     BOOL bResetToDefault
		, __in_opt PTOKEN_GROUPS pNewState = NULL
		, __in     DWORD nBufferLength = 0
		, __out_bcount_part_opt(nBufferLength, *pnReturnLength)
		            PTOKEN_PRIVILEGES pPreviousState = NULL
		, __out_opt PDWORD pnReturnLength            = NULL
		) const
	{
		_ASSERTE(IsValid());

		return ::AdjustTokenGroups(m_h, bResetToDefault, pNewState
			, nBufferLength, pPreviousState, pnReturnLength);
	}

	BOOL PrivilegeCheck
		( __inout PPRIVILEGE_SET pRequiredPrivileges
		, __out   LPBOOL         pbResult
		) const
	{
		_ASSERTE(IsValid());

		return ::PrivilegeCheck(m_h, pRequiredPrivileges, pbResult);
	}

	int PrivilegeCheck
		( __inout PPRIVILEGE_SET pRequiredPrivileges
		) const
	{
		_ASSERTE(IsValid());
		BOOL pbResult;
	
		return ::PrivilegeCheck(m_h, pRequiredPrivileges, &bResult)? !!bResult: -1;
	}

	BOOL ObjectOpenAuditAlarm
		( __in     LPCSTR               lpSubsystemName
		, __in     LPVOID               lpHandleId
		, __in     LPCSTR               lpObjectTypeName
		, __in_opt LPCSTR               lpObjectName
		, __in     PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in     DWORD                nDesiredAccess
		, __in     DWORD                nGrantedAccess
		, __in_opt PPRIVILEGE_SET       pPrivileges
		, __in     BOOL                 bObjectCreation
		, __in     BOOL                 bAccessGranted
		, __out    LPBOOL               lpbGenerateOnClose
		) const
	{
		_ASSERTE(IsValid());

		return ::ObjectOpenAuditAlarmA(lpSubsystemName, lpHandleId
			, lpObjectTypeName, lpObjectName, pSecurityDescriptor
			, m_h, nDesiredAccess, nGrantedAccess, pPrivileges
			, bObjectCreation, bAccessGranted, lpbGenerateOnClose);
	}

	BOOL ObjectOpenAuditAlarm
		( __in     LPCWSTR              lpSubsystemName
		, __in     LPVOID               lpHandleId
		, __in     LPCWSTR              lpObjectTypeName
		, __in_opt LPCWSTR              lpObjectName
		, __in     PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in     DWORD                nDesiredAccess
		, __in     DWORD                nGrantedAccess
		, __in_opt PPRIVILEGE_SET       pPrivileges
		, __in     BOOL                 bObjectCreation
		, __in     BOOL                 bAccessGranted
		, __out    LPBOOL               lpbGenerateOnClose
		) const
	{
		_ASSERTE(IsValid());

		return ::ObjectOpenAuditAlarmW(lpSubsystemName, lpHandleId
			, lpObjectTypeName, lpObjectName, pSecurityDescriptor
			, m_h, nDesiredAccess, nGrantedAccess, pPrivileges
			, bObjectCreation, bAccessGranted, lpbGenerateOnClose);
	}

	BOOL ObjectPrivilegeAuditAlarm
		( __in LPCSTR         lpSubsystemName
		, __in LPVOID         lpHandleId
		, __in DWORD          nDesiredAccess
		, __in PPRIVILEGE_SET pPrivileges
		, __in BOOL           bAccessGranted
		) const
 	{
		_ASSERTE(IsValid());

		return ::ObjectPrivilegeAuditAlarmA(lpSubsystemName, lpHandleId
			, m_h, nDesiredAccess, pPrivileges, bAccessGranted);
	}

	BOOL ObjectPrivilegeAuditAlarm
		( __in LPCWSTR        lpSubsystemName
		, __in LPVOID         lpHandleId
		, __in DWORD          nDesiredAccess
		, __in PPRIVILEGE_SET pPrivileges
		, __in BOOL           bAccessGranted
		) const
 	{
		_ASSERTE(IsValid());

		return ::ObjectPrivilegeAuditAlarmW(lpSubsystemName, lpHandleId
			, m_h, nDesiredAccess, pPrivileges, bAccessGranted);
	}

	BOOL PrivilegedServiceAuditAlarm
		( __in LPCSTR         lpSubsystemName
		, __in LPCSTR         lpServiceName
		, __in PPRIVILEGE_SET pPrivileges
		, __in BOOL           bAccessGranted
		) const
 	{
		_ASSERTE(IsValid());

		return ::PrivilegedServiceAuditAlarmA(lpSubsystemName, lpServiceName
			, m_h, pPrivileges, bAccessGranted);
	}

	BOOL PrivilegedServiceAuditAlarm
		( __in LPCWSTR        lpSubsystemName
		, __in LPCWSTR        lpServiceName
		, __in PPRIVILEGE_SET pPrivileges
		, __in BOOL           bAccessGranted
		) const
 	{
		_ASSERTE(IsValid());

		return ::PrivilegedServiceAuditAlarmW(lpSubsystemName, lpServiceName
			, m_h, pPrivileges, bAccessGranted);
	}

	BOOL CreatePrivateObjectSecurity
		( __in_opt    PSECURITY_DESCRIPTOR  pParentDescriptor
		, __in_opt    PSECURITY_DESCRIPTOR  pCreatorDescriptor
		, __deref_out PSECURITY_DESCRIPTOR *ppNewDescriptor
		, __in        BOOL                  bIsDirectoryObject
		, __in        PGENERIC_MAPPING      pGenericMapping
		) const
 	{
		_ASSERTE(IsValid());

		return ::CreatePrivateObjectSecurity(pParentDescriptor
			, pCreatorDescriptor, ppNewDescriptor, bIsDirectoryObject
			, m_h, pGenericMapping);
	}

	BOOL SetPrivateObjectSecurity
		( __in          SECURITY_INFORMATION  SecurityInformation
		, __in          PSECURITY_DESCRIPTOR  pModificationDescriptor
		, __deref_inout PSECURITY_DESCRIPTOR *ppObjectsSecurityDescriptor
		, __in          PGENERIC_MAPPING      pGenericMapping
		) const
 	{
		_ASSERTE(IsValid());

		return ::SetPrivateObjectSecurity( SecurityInformation
			, pModificationDescriptor, pModificationDescriptor
			, pGenericMapping, m_h);
	}

	BOOL CheckMembership
		( __in  PSID  pSidToCheck
		, __out PBOOL pbIsMember
		) const
 	{
		_ASSERTE(pbIsMember);

		return ::CheckTokenMembership(m_h, pSidToCheck, pbIsMember);
	}

	int CheckMembership
		( __in PSID pSidToCheck
		) const
 	{
		BOOL bIsMember;

		return ::CheckTokenMembership(m_h, pSidToCheck, &bIsMember)? !!bIsMember: -1;
	}

#if _WIN32_WINNT >= 0x0500

	BOOL AccessCheckByType
		( __in     PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in_opt PSID                 pPrincipalSelfSid
		, __in     DWORD                nDesiredAccess
		, __inout_ecount_opt(nObjectTypeListLength)
		           POBJECT_TYPE_LIST    pObjectTypeList
		, __in     DWORD                nObjectTypeListLength
		, __in     PGENERIC_MAPPING     pGenericMapping
		, __out_bcount_part_opt(*lpnPrivilegeSetLength, *lpnPrivilegeSetLength)
		           PPRIVILEGE_SET       pPrivilegeSet
		, __inout  LPDWORD              lpnPrivilegeSetLength
		, __out    LPDWORD              lpnGrantedAccess
		, __out    LPBOOL               lpbAccessStatus
		) const
	{
		_ASSERTE(IsValid());

		return ::AccessCheckByType(pSecurityDescriptor, pPrincipalSelfSid
			, m_h, nDesiredAccess, pObjectTypeList, nObjectTypeListLength
			, pGenericMapping, pPrivilegeSet, lpnPrivilegeSetLength
			, lpnGrantedAccess, lpbAccessStatus);
	}

	BOOL AccessCheckByTypeResultList
		( __in     PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in_opt PSID                 pPrincipalSelfSid
		, __in     DWORD                nDesiredAccess
		, __inout_ecount_opt(nObjectTypeListLength)
		           POBJECT_TYPE_LIST    pObjectTypeList
		, __in     DWORD nObjectTypeListLength
		, __in     PGENERIC_MAPPING     pGenericMapping
		, __out_bcount_part_opt(*lpnPrivilegeSetLength, *lpnPrivilegeSetLength)
		           PPRIVILEGE_SET       pPrivilegeSet
		, __inout  LPDWORD              lpnPrivilegeSetLength
		, __out    LPDWORD              lpnGrantedAccess
		, __out    LPDWORD              lpnAccessStatusList
		) const
	{
		_ASSERTE(IsValid());

		return ::AccessCheckByTypeResultList(pSecurityDescriptor, pPrincipalSelfSid
			, m_h, nDesiredAccess, pObjectTypeList, nObjectTypeListLength
			, pGenericMapping, pPrivilegeSet, lpnPrivilegeSetLength
			, lpnGrantedAccess, lpnAccessStatusList);
	}

	BOOL AccessCheckByTypeResultListAndAuditAlarmByHandle
		( __in     LPCSTR               lpSubsystemName
		, __in     LPVOID               lpHandleId
		, __in     LPCSTR               lpObjectTypeName
		, __in_opt LPCSTR               lpObjectName
		, __in     PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in_opt PSID                 pPrincipalSelfSid
		, __in     DWORD                nDesiredAccess
		, __in     AUDIT_EVENT_TYPE     AuditType
		, __in     DWORD                nFlags
		, __inout_ecount_opt(nObjectTypeListLength)
		           POBJECT_TYPE_LIST    pObjectTypeList
		, __in     DWORD                nObjectTypeListLength
		, __in     PGENERIC_MAPPING     pGenericMapping
		, __in     BOOL                 bObjectCreation
		, __out    LPDWORD              pnGrantedAccess
		, __out    LPDWORD              pnAccessStatusList
		, __out    LPBOOL               lpbGenerateOnClose
		) const
	{
		_ASSERTE(IsValid());

		return ::AccessCheckByTypeResultListAndAuditAlarmByHandleA
			( lpSubsystemName, lpHandleId, m_h, lpObjectTypeName
			, lpObjectName, pSecurityDescriptor, pPrincipalSelfSid
			, nDesiredAccess, AuditType, nFlags, pObjectTypeList
			, nObjectTypeListLength, pGenericMapping, pnGrantedAccess
			, pnAccessStatusList, lpbGenerateOnClose);
	}

	BOOL AccessCheckByTypeResultListAndAuditAlarmByHandle
		( __in     LPCWSTR              lpSubsystemName
		, __in     LPVOID               lpHandleId
		, __in     LPCWSTR              lpObjectTypeName
		, __in_opt LPCWSTR              lpObjectName
		, __in     PSECURITY_DESCRIPTOR pSecurityDescriptor
		, __in_opt PSID                 pPrincipalSelfSid
		, __in     DWORD                nDesiredAccess
		, __in     AUDIT_EVENT_TYPE     AuditType
		, __in     DWORD                nFlags
		, __inout_ecount_opt(nObjectTypeListLength)
		           POBJECT_TYPE_LIST    pObjectTypeList
		, __in     DWORD                nObjectTypeListLength
		, __in     PGENERIC_MAPPING     pGenericMapping
		, __in     BOOL                 bObjectCreation
		, __out    LPDWORD              pnGrantedAccess
		, __out    LPDWORD              pnAccessStatusList
		, __out    LPBOOL               lpbGenerateOnClose
		) const
	{
		_ASSERTE(IsValid());

		return ::AccessCheckByTypeResultListAndAuditAlarmByHandleW
			( lpSubsystemName, lpHandleId, m_h, lpObjectTypeName
			, lpObjectName, pSecurityDescriptor, pPrincipalSelfSid
			, nDesiredAccess, AuditType, nFlags, pObjectTypeList
			, nObjectTypeListLength, pGenericMapping, pnGrantedAccess
			, pnAccessStatusList, lpbGenerateOnClose);
	}

	BOOL CreatePrivateObjectSecurityEx
		( __in_opt    PSECURITY_DESCRIPTOR  pParentDescriptor
		, __in_opt    PSECURITY_DESCRIPTOR  pCreatorDescriptor
		, __deref_out PSECURITY_DESCRIPTOR *ppNewDescriptor
		, __in_opt    GUID                 *pObjectType
		, __in        BOOL                  bIsContainerObject
		, __in        ULONG                 nAutoInheritFlags
		, __in        PGENERIC_MAPPING      pGenericMapping
		) const
 	{
		_ASSERTE(IsValid());

		return ::CreatePrivateObjectSecurityEx(pParentDescriptor
			, pCreatorDescriptor, ppNewDescriptor, pObjectType
			, bIsContainerObject, nAutoInheritFlags, m_h, pGenericMapping);
	}

	BOOL CreatePrivateObjectSecurityWithMultipleInheritance
		( __in_opt                    PSECURITY_DESCRIPTOR  pParentDescriptor
		, __in_opt                    PSECURITY_DESCRIPTOR  pCreatorDescriptor
		, __deref_out                 PSECURITY_DESCRIPTOR *ppNewDescriptor
		, __in_ecount_opt(nGuidCount) GUID                **ppObjectTypes
		, __in                        ULONG                 nGuidCount
		, __in                        BOOL                  bIsContainerObject
		, __in                        ULONG                 nAutoInheritFlags
		, __in                        PGENERIC_MAPPING      pGenericMapping
		) const
 	{
		_ASSERTE(IsValid());

		return ::CreatePrivateObjectSecurityWithMultipleInheritance
			( pParentDescriptor, pCreatorDescriptor, ppNewDescriptor
			, ppObjectTypes, nGuidCount, bIsContainerObject
			, nAutoInheritFlags, m_h, pGenericMapping);
	}

	BOOL SetPrivateObjectSecurityEx
		( __in          SECURITY_INFORMATION  SecurityInformation
		, __in          PSECURITY_DESCRIPTOR  pModificationDescriptor
		, __deref_inout PSECURITY_DESCRIPTOR *ppObjectsSecurityDescriptor
		, __in          ULONG                 nAutoInheritFlags
		, __in          PGENERIC_MAPPING      pGenericMapping
		) const
 	{
		_ASSERTE(IsValid());

		return ::SetPrivateObjectSecurityEx( SecurityInformation
			, pModificationDescriptor, pModificationDescriptor
			, nAutoInheritFlags, pGenericMapping, m_h);
	}

	BOOL CreateProcessWith
		( __in        DWORD          dwLogonFlags
		, __in_opt    LPCWSTR        lpApplicationName
		, __inout_opt LPWSTR         lpCommandLine
		, __in        DWORD          dwCreationFlags
		, __in_opt    LPVOID         lpEnvironment
		, __in_opt    LPCWSTR        lpCurrentDirectory
		, __in        LPSTARTUPINFOW lpStartupInfo
		, __out_opt   LPHANDLE       lphProcess   = NULL
		, __out_opt   LPHANDLE       lphThread    = NULL
		, __out_opt   LPDWORD        lpnProcessId = NULL
		, __out_opt   LPDWORD        lpnThreadId  = NULL
		) const
{
		_ASSERTE(lpApplicationName || lpCommandLine);
		_ASSERTE(IsValid());

		return HTL::CreateProcessWithToken(m_h, dwLogonFlags
			, lpApplicationName, lpCommandLine, dwCreationFlags, lpStartupInfo
			, lpEnvironment, lpCurrentDirectory, lphProcess, lphThread
			, lpnProcessId, lpnThreadId);
	}
#endif // _WIN32_WINNT >= 0x0500
};

typedef CTokenT<true>  CToken;
typedef CTokenT<false> CTokenHandle;

#ifdef _INC_TOOLHELP32

/////////////////////////////////////////////////////////////////////////////
// ToolhelpSnapshot

template<bool t_bManaged>
class CToolhelpSnapshotT
	: public CHandleT<t_bManaged>
{
	typedef CHandleT<t_bManaged> Base;
public:

	CToolhelpSnapshotT()
	{ }
	CToolhelpSnapshotT
		( __in const CToolhelpSnapshotT<true>& rToolhelpSnapshot
		)
		: Base(rToolhelpSnapshot)
	{ }
	CToolhelpSnapshotT
		( __in const CToolhelpSnapshotT<false>& rToolhelpSnapshot
		)
		: Base(rToolhelpSnapshot)
	{ }
	explicit CToolhelpSnapshotT
		( __in HANDLE hToolhelpSnapshot
		)
		: Base((INVALID_HANDLE_VALUE != hToolhelpSnapshot) ? hToolhelpSnapshot : NULL)
	{ }

	explicit CToolhelpSnapshotT
		( __in DWORD nFlags
		, __in DWORD nProcessId = 0
		)
	{
		Create(nFlags, nProcessId);
		_ASSERTE(IsValid());
	}

	CToolhelpSnapshotT<t_bManaged>& operator=
		( __in HANDLE h
		)
	{
		Base::operator=((INVALID_HANDLE_VALUE != h) ? h : NULL);
		return *this;
	}

	CToolhelpSnapshotT<t_bManaged>& operator=
		( __in const CToolhelpSnapshotT<true>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	CToolhelpSnapshotT<t_bManaged>& operator=
		( __in const CToolhelpSnapshotT<false>& other
		)
	{
		Base::operator=(other);
		return *this;
	}

	HANDLE Create
		( __in DWORD nFlags
		, __in DWORD nProcessId = 0
		)
	{
		_ASSERTE(!IsValid());
		HANDLE h;

		h = ::CreateToolhelp32Snapshot(nFlags, nProcessId);
		if (INVALID_HANDLE_VALUE == h)
			h = NULL;
		return m_h = h;
	}

	BOOL First
		( __inout LPHEAPLIST32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(HEAPLIST32));
		_ASSERTE(IsValid());

		return ::Heap32ListFirst(m_h, pData);
	}

	BOOL Next
		( __inout LPHEAPLIST32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(HEAPLIST32));
		_ASSERTE(IsValid());

		return ::Heap32ListNext(m_h, pData);
	}

	BOOL First
		(__inout LPPROCESSENTRY32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(PROCESSENTRY32));
		_ASSERTE(IsValid());

		return ::Process32First(m_h, pData);
	}

	BOOL Next
		( __inout LPPROCESSENTRY32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(PROCESSENTRY32));
		_ASSERTE(IsValid());

		return ::Process32Next(m_h, pData);
	}

#ifndef UNICODE
	BOOL First
		( __inout LPPROCESSENTRY32W pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(PROCESSENTRY32W));
		_ASSERTE(IsValid());

		return ::Process32FirstW(m_h, pData);
	}

	BOOL Next
		( __inout LPPROCESSENTRY32W pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(PROCESSENTRY32W));
		_ASSERTE(IsValid());

		return ::Process32NextW(m_h, pData);
	}
#endif // UNICODE

	BOOL First
		( __inout LPMODULEENTRY32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(MODULEENTRY32));
		_ASSERTE(IsValid());

		return ::Module32First(m_h, pData);
	}

	BOOL Next
		( __inout LPMODULEENTRY32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(MODULEENTRY32));
		_ASSERTE(IsValid());

		return ::Module32Next(m_h, pData);
	}

#ifndef UNICODE
	BOOL First
		( __inout LPMODULEENTRY32W pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(MODULEENTRY32W));
		_ASSERTE(IsValid());

		return ::Module32FirstW(m_h, pData);
	}

	BOOL Next
		( __inout LPMODULEENTRY32W pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(MODULEENTRY32W));
		_ASSERTE(IsValid());

		return ::Module32NextW(m_h, pData);
	}
#endif // UNICODE

	BOOL First
		( __inout LPTHREADENTRY32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(THREADENTRY32));
		_ASSERTE(IsValid());

		return ::Thread32First(m_h, pData);
	}

	BOOL Next
		( __inout LPTHREADENTRY32 pData
		) const
	{
		_ASSERTE(pData && pData->dwSize == sizeof(THREADENTRY32));
		_ASSERTE(IsValid());

		return ::Thread32Next(m_h, pData);
	}
};

typedef CToolhelpSnapshotT<true>  CToolhelpSnapshot;
typedef CToolhelpSnapshotT<false> CToolhelpSnapshotHandle;

#endif // _INC_TOOLHELP32

/////////////////////////////////////////////////////////////////////////////

}	// namespace HTL

/////////////////////////////////////////////////////////////////////////////

#endif	// #ifndef __HTLPROC_H__

/////////////////////////////////////////////////////////////////////////////
// End Of File htlproc.h
